#1 2015-10-14 AOP讨论java
强烈推荐文章正则表达式
本文则是根据上述文章进行的群内讨论的提纲编程
#2 从AOP拦截的时机来看待AOPjvm
如图:ide
1 aspectj : 在编译期静态植入工具
2 JDK Proxy: 目标类加载后,为其接口动态生成代理类this
3 cglib : 目标类加载后,为其动态生成子类,将切面逻辑加入子类中.net
4 自定义类加载器:在目标类加载前,将切面逻辑加入目标类字节码中代理
5 字节码转换器:在目标类加载前,将切面逻辑加入目标类字节码中(jdk1.5的Instrumentation);在目标类加载后,将切面逻辑加入目标类字节码中(jdk1.6的Instrumentation触发jvm从新类加载)日志
在类的字节码载入jvm前会调用ClassFileTransformer的transform方法,从而实现修改原类方法的功能,实现aop
如日志记录工具anylog,就是使用自定义的ClassFileTransformer来动态修改字节码(内部借助于javassist来修改字节码)
#3 角色梳理:AOP联盟、Aspectj、SpringAOP
##3.1 AOP的概念
Pointcut:切入点,表示在哪里进行拦截,简单理解如正则表达式
Joinpoint:链接点,符合上述正则表达式的一个具体对象
Advice:加强,即拦截逻辑
Advice的类型:
Aspect:切面,包含切入点和加强
Target Object:要代理的目标对象
AOP Proxy:代理对象
Weaving:织入,能够是编译期、字节码加载前、字节码加载后
##3.2 Aspectj
以下简单使用案例:
这里有个系列文章跟我学aspectj
#4 SpringAOP的发展历程
##4.1 JDK和CGLib动态代理的原始方式
JDK动态代理:
CGLib动态代理:
##4.2 ProxyFactory对jdk和cglib的封装
ProxyFactory简单的对jdk和cglib的封装,根据配置(强制采用cglib)或者自行决定(根据是否实现接口)采用jdk动态代理仍是cglib动态代理。
使用案例以下:
对jdk动态代理的封装(cglib也相似再也不说明):
InvocationHandler h:固定是JdkDynamicAopProxy,其中对
InvocationHandler的接口方法Object invoke(Object proxy, Method method, Object[] args)实现以下:
第一步:根据调用的类和方法获取拦截器MethodInterceptor集合,内部会使用pointcut来进行过滤。后面详细说说MethodInterceptor和Advice的区别。
ProxyFactory有以下两种方法:
addAdvice(Advice advice) addAdvisor(Advisor advisor)
Advisor:实际上是Advice和Pointcut的集合,因此在添加Advice是会给出一个默认的Pointcut
Pointcut能够是:
正则表达式类型 JdkRegexpMethodPointcut
aspectj的pointcut表达式类型,如
execution(* com.aspectj.demo.test.HelloWorld.main(..)) @annotation(aop.demo.Tag)
第二步:若是拦截器集合为空(即没有代理该方法),则经过反射直接执行目标对象target的方法
第三步:若是拦截器集合不为空,依次执行拦截器MethodInterceptor中的invoke方法。
MethodInterceptor和Advice的区别:
Advice:定义了拦截逻辑,如MethodBeforeAdvice,接口定义以下:
public interface MethodBeforeAdvice extends BeforeAdvice { void before(Method method, Object[] args, Object target) throws Throwable; }
而MethodInterceptor则是决定Advice的调用时机,同时对外提供统一的调用方法invoke,如MethodBeforeAdviceInterceptor
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); } }
上述就是ProxyFactory对jdk和cglib的封装,简化了咱们的操做。可是还有以下问题:
##4.3 批量代理
上述ProxyFactory还只能针对某一个target进行代理
咱们如今的需求是:对一批对象进行批量代理。这时须要两大部分:
一批Advice和Pointcut组合,即会有多个Advisor,符合不一样Pointcut的进行不一样的Advice加强。这里即切面,切面并无具体的类进行描述,能够理解成一个Advisor的集合(一个Advisor包含了一个Advice和一个Pointcut),以下所示
如xml配置形式配置切面:
注解形式配置切面,同时要开启aop:aspectj-autoproxy配置:
切面仅仅是描述哪些类的哪些方法被哪些Advice加强,仅仅是描述而已,须要有一个类来承担这样的批量代理的工做,这就是基类AbstractAutoProxyCreator来完成这一项工做,对于每个符合条件的bean都仍然采用ProxyFactory来进行代理的建立:
因此Spring中的AOP所有是基于ProxyFactory这套建立流程的。而AbstractAutoProxyCreator子类则是分别取解析不一样的切面配置
如上述的aop:config配置是启用了AspectJAwareAdvisorAutoProxyCreator来进行批量代理的
如上述注解形式开启的aop:aspectj-autoproxy是启用了AnnotationAwareAspectJAutoProxyCreator来进行批量代理的
##4.4 Spring对aspectj的引入的体现
咱们知道aspectj是静态织入,Spring是怎么来引入aspectj呢?
aspectj是静态织入,须要单独的编译器来进行编译,可是功能强大。如使用案例:
强大的pointcut表达式功能(具体的自行去搜),同时还具备了注解功能,以下:
等这些都是aspectj的实现
而什么才叫Spring最原始的AOP呢?就是ProxyFactory这一层,仅仅对jdk和cglib进行了简单的封装。
Spring原始的ProxyFactory代理,手动编程或配置进行代理都比较麻烦,引入了aspectj的某些功能
可是引入以后呢,仍是所有转化成Spring本来的Advisor,最终仍然使用本来的ProxyFactory来建立代理,而不是像aspectj那样须要单独的编译器。