基础
AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础。它是一种面向切面编程的思想。关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来讲解下AOP的核心功能的底层实现机制:如何用动态代理来实现切面拦截。
配置
注意:在一般整合的框架中,application是spring的配置文件,SpringMVC-servlet.xml才是SpringMVC的配置文件,我们是在SpringMVC上面配置aop,所以我们需要把配置文件都设置到SpringMVC-servlet.xml中.
一、在配置文件中配置相关的东西
1. 书写aop对象如AopDemo
2. SpringMVC-servlet.xml
2.1开自动扫描,
必须在aop:pointcut中的匹配到类扫描到了SpringMVC中,
2.2书写:execution
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
有“?”号的部分表示可省略的,modifers-pattern表示修饰符如public、protected等,ret-type-pattern表示方法返回类型,declaring-type-pattern代表特定的类,name-pattern代表方法名称,param-pattern表示参数,throws-pattern表示抛出的异常。在切入点表达式中,可以使用*来代表任意字符,用..来表示任意个参数。
2.3 op:after aop:after-returningaop:before中的配置:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
Object result;
try {
//@Before
result = method.invoke(target, args);
//@After
return result;
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
//@AfterThrowing
throw targetException;
} finally {
//@AfterReturning
}
}
After-returning配置里面可以增强返回值,可以在配置文件中加上returning标签 <aop:after-returningreturning="ret" method="AfterDemo"pointcut-ref="test"/>
Ret就是参数名称,方法中AfterDemo(Object ret)
aop:around环绕参数为ProceedingJoinPoint类型
方法中接收roundDemo(ProceedingJoinPoint point)
二、在aop对象中使用注解,不在配置文件中配置
但是得在配置文件中打开aop注解:
<aop:aspectj-autoproxyexpose-proxy="true"></aop:aspectj-autoproxy>
@Component
@Aspect
public classHelloApiAspect2 {
@Pointcut(value="execution(*bean.HelloApi.aspectTest(..)) &&args(a1,b2)",argNames="a1,b2")
publicvoidpointcut1(String a1,String b2){}
@Before(value="pointcut1(a,b)",argNames="a,b")
publicvoidbeforecase1(String a,String b){
System.out.println("1 a:" +a +" b:" + b);
}
//注意和beforecase1的区别是argNames的顺序交换了
@Before(value="pointcut1(a,b)",argNames="b,a")
publicvoidbeforecase2(String a,String b){
System.out.println("2 a:" +a +" b:" + b);
}
@AfterReturning(value="pointcut1(a,b)",returning="ret")
publicvoid AfterReturnDemo(Object ret) {
Cbsf c = (Cbsf)ret;
System.out.println(c.get_id() +":" + c.getAzlx());
}
}
原理
AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。
那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。
AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。
ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
区别
此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理
CGLIB(CODEGENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxyproxy-target-class="true"/>)
http://blog.csdn.net/zbuger/article/details/51011117