aop即aspect oriented programming,是spring的核心功能之一,其充分利用了ioc容器的proxy代理以及aop的拦截器功能,以下从三方面进行梳理。
spring框架中默认是关闭aop功能的,在项目中需要开启AOP功能即<aop:aspectj-autoproxy/>
一、aop的基本概念
1.1:advice(通知)定义在连接点做什么,为切面增强提供织入接口,有BeforeAdvice,AfterAdvice,ThrowsAdvice等,会在调用目标方法前,后,异常的时候,通过jdk反射机制回调
1.2:PointCut(切点)需要增强的方法的集合,决定advice作用于哪个连接点,通常意味着标识方法,可以通过正则表达式或者方法名进行定义。
1.2.1:JdkRegexpMethodPointcut
使用jdk正则表达式对方法名进行匹配
1.2.2:NameMatchMethodPointcut
方法名进行匹配
1.3:Advisor通知器,定义使用哪个通知在哪个切点使用,将Advice和Pointcur结合,达到即开即用,比如DefaultPointcutAdvisor
二、jdk动态proxy代理对象的生成
2.1:代理模式概念
实现被代理对象的接口并且拥有被代理对象的一个对象,进行方法前后额外的处理如preOperation,postOperation。具体如Object invoke(Object proxy, Method method, Object[] args)这个是java中自带的Proxy对象处理代理的业务,其中,proxy指代理对象实例、Method指当前Proxy被调用的方法、args指调用方法中的参数,一般需要Proxy.newInstance方法生成Proxy对象然后调用即可
2.2:JdkDynamicAopProxy
是默认的aop应用中产生aopproxy代理对象的,代理对象是某个接口的实现,在运行期间创建一个接口的实现完成代理东南。相关的拦截器已经配置到代理对象中,通过实现AopProxy, InvocationHandler接口,以及直接构造ReflectiveMethodInvocation的invoke方法完成拦截器链的调用,在proxy对象代理的方法被调用时,调用invoke方法会被触发,完成拦截器链的读取以及缓存,从而实现对目标对象方法调用的功能增强。通过AopUtils.invokeJoinpointUsingReflection的反射机制method.invoke实现目标方法的调用
2.3:Cglib2AopProxy
通过构造在CglibMethodInvocation(也继承了ReflectiveMethodInvocation)对象完成拦截器链的调用,回调是在DynamicAdvisedInterceptor对象中的intercept方法中实现,通过methodProxy.invoke实现目标方法的调用,要使用该代理需<aop:aspectj-autoproxy proxy-target-class="true"/>进行强制使用,
三、拦截器的应用
3.1:以上aopProxy对象中分别介绍了构造不同的回调方法启动对拦截器链的调用以及目标方法的调用,最终通过ReflectiveMethodInvocation.proceed进行调用拦截器中的拦截方法
3.2:aop拦截器链的应用
在ReflectiveMethodInvocation.proceed方法中,先依次对拦截器进行matches判断是否适用于横切增强的条件,若符合,则调用其通知器的方法并计数。然后递归调用proceed方法至链尾。
3.3:Advice通知实现
四:框架应用
4.1:增强器的提取BeanFactoryAspectJAdvisorsBuilder
在buildAspectJAdvisors从beanFactory中获取所有注册的bean,遍历beanName找出声明AspectJ注解的类,进行增强提取放入缓存中中。
4.2:切点信息的获取AspectJExpressionPointcut
通过getPointcut获取方法上面的注解进而得到表达式如@Pointcut(“execution(* *.*test*(..))”),然后使用AspectJAnnotation进行封装
4.3:切点信息增强InstantiationModelAwarePointcutAdvisorImpl
根据不同的注解类型进行不同增强器的调用如MethodBeforeAdviceInterceptor方法调用前处理,AspectJAfterAdvice方法finally中调用
4.4:创建代理
在源码中通过判断isOptimize(是否使用激进的优化策略)、isProxyTargetClass(代理对象本身)、hasNoUserSuppliedProxyInterfaces(无代理接口)进而选择哪种代理
五:静态代理
<context:load-tme-weaver/> 载入字节码文件的时候完成对目标对象的增强,而动态代理在调用的时候需要动态创建代理以及代理对象,相比较而言,前者效率高