spring AOP
Spring AOP(面向切面编程):
那么切面(aspect)是啥?
一个关注点的模块化,通常是一个类;通常会横切多个对象;
再来说说为什么要有aop,我们都知道java是面向对象的语言,3大特性,封装、继承、多态。我们使用类来区别不同兑现,类是对一类“事物”的属性与行为的抽象。那么现在我们我们需要做一个日志系统,来记录操作,输出日志信息这个功能并不是其它类的属性或者行为,也就是和其他类并没有太多的关系,因此我们需要写一个日志类,那么问题来了!!既然是日志,系统中肯定有许多地方需要用到,那么在需要用到的地方,我们就需要调用,一旦需要修改的时候,极为不便,那么面向切向编程(AOP)就可以很好的解决这个问题!
理解:Aop就是将动态代理封装了起来,只用写好的真实对象,和额外实现的方法也就是公共业务,在不改变源代码的基础上,插入了功能,实现了公共业务的重复利用,这样也提高了开发效率;
现在来看看spring aop 的一些名词:
关注点:增加的某个业务,例如:日志,安全,事务等;
切面(aspect):一个关注点的模块化,通常是一个类;通常会横切多个对象;
连接点(JoinPoint):某个方法的执行
通知(advice):在切面的某个连接点上执行的特定的动作。包括了around、before。After等不同类型的通知;
织入(Weaving):把切面连接其它的应用程序类型或者对象上,并创建一个被通知的对象
使用spring实现aop:
支持:java 5.0引入了java.lang.instrument,允许在jvm启动时启用一个代理类,通过该代理类在运行期间修改类的字节码,改变一个类的功能,实现AOP功能;
第一种是实现方式-通过spring APi来实现:
实现MethodBeforeAdvice接口:
public class Log implements MethodBeforeAdvice{
/**
* @param method 被调用方法对象
* @param args 被调用的方法的参数
* @param target 被调用的方法的目标对象
* */
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行");
}
}
配置文件使Log类和对应的类进行关联;
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.ccc.service.impl.UserServiceImpl"/>
<bean id="log" class="com.ccc.log.Log"/>
<aop:config>
<aop:pointcut expression="execution(* com.ccc.service.impl.UserServiceImpl.add())" id="pointcut"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
</aop:config>
</beans>
com.ccc.service.impl.UserServiceImpl.add()
execution中为被切的对象方法,可以想象成把日志功能横切嵌入进去
.add()表示add方法, 表示所有方法可以用.*() ()表示无参数,而有参可以用(..)表示所有个数的参数
运行结果:
com.ccc.service.impl.UserServiceImpl的add方法被执行
增加用户
第二种实现方式:通过自定义类来实现
public class UserService {
public void add(){
System.out.println("i am add method");
}
public void delete(){
System.out.println("i am delete method");
}
public class Log {
public void beforelog(){
System.out.println("i am beforelog");
}
public void afterlog(){
System.out.println("i am afterlog");
}
}
配置文件:
<bean id="service" class="com.czy.service.UserService"/>
<bean id="log" class="com.czy.log.Log"/>
<aop:config>
<aop:aspect ref="log"><!--引入切面类-->
<aop:pointcut expression="execution(* com.czy.service.UserService.*())" id="pointcut"/>
<aop:before method="beforelog" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
可以看出在执行add方法的时候,拦截器拦截,先输出了日志;
第三种方式:通过注解实现aop
说实话,个人感觉前两种配置文件太繁琐了.....第三中方法的配置文件如下(头部dtd约束省略):
<bean id="service" class="com.czy.service.UserService"/>
<bean id="log" class="com.czy.log.Log"/>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
这样就一条....使用spring的配置自动完成创建代理织入切面的工作。
//表示这是一个切面
@Aspect
public class Log {
@Before("execution(* com.czy.service.UserService.*())")
public void beforelog(){
System.out.println("i am beforelog");
}
public void afterlog(){
System.out.println("i am afterlog");
}
}
注解: @Aspect:表示这是一个切面
@Before:在方法执行前执行
@Around:环绕,在前后都执行一次
//表示这是一个切面
@Aspect
public class Log {
@Before("execution(* com.czy.service.UserService.*())")
public void beforelog(){
System.out.println("i am beforelog");
}
@After("execution(* com.czy.service.UserService.*())")
public void afterlog(){
System.out.println("i am afterlog");
}
环绕通知与前置后置通过不同,需要带一个参数
@Around("execution(* com.czy.service.UserService.*())")
public void aroundlog(ProceedingJoinPoint pjp){
System.out.println("abefore log");
System.out.println(pjp.getSignature());
System.out.println("aafter log");
运行结果:
上一篇: Spring AOP
下一篇: spring AOP