内容简介:微热山丘,探索 IoC、AOP 实现原理(二) AOP 实现原理
AOP 实现原理
一、简介
AOP 是 Aspect Oriented Programming 的简写,面向切面编程。主要的作用是 以一种统一的方式对程序的逻辑进行修改、增强处理。 可以在编译时也可以在运行时实现。编译时处理一般是通过字节码处理技术,运行时进行的一般是通过动态代理技术实现。
二、AOP 核心概念
- Concerns, 关注 :有两类,核心关注–是关于业务逻辑的;横切关注–是一些通用的逻辑,比如日志、缓存。
- Joinpoint, 连接点 :是执行时的切入点。可以是字段访问也可以是被调用方法。基于动态代理技术实现的一般只支持方法调用的连接点。
- Target, 目标 :是一个被切入的地方,一般是一个业务逻辑。比如是对一个业务逻辑的方法的调用。
- Pointcut, 切入点 :并不是所有的连接点都需要切入,切入点用于指定哪些连接点需要切入。
- Advice, 建议 :定义了 Aspect 的任务和什么时候执行它,是在核心关注之前还是之后。
- Aspect, 方面 :Advice 和 pointcut 定义一个方面。Advice 定义 Aspect 的任务和什么时候执行它,而切入点 pointcut 定义在哪里具体地方切入。就是说 Aspect 定义了它是什么东西、什么时候切入和在哪里切入。
- Weaving, 织入 :织入是一个把横切方面混合到业务目标对象的过程。可以是在编译时间,也可以是在运行时使用类加载机制,Spring AOP 是在运行时生成 bean 时处理。
下面是在 Sping 的 XML 里定义一个 AOP 的配置,注意其中个元素间的关系:
<!-- 一个 weaving 的定义 --> <aop:config> <!-- 定义 aspect, ref 指向 任务的定义 --> <aop:aspect id="aspectCommonLogHandler" ref="commonLogHandler"> <!-- 定义 pointcut --> <aop:pointcut id="commonLogPointcut" expression="execution( * net.coderbee.*.controller..*.*(..))" /> <!-- 定义 advice, around 表示在目标的前/后执行 --> <aop:around method="inceptor" pointcut-ref="commonLogPointcut" /> </aop:aspect> </aop:config>
三、AOP 实现
1. 各组件定义配置
warnhill 的 AOP 实现没有采用 Spring 那样的配置方式,而是采用 bean 定义的形式组织起来:
<!-- 定义织入逻辑的实现 --> <bean id="aspectJAutoProxyCreator" class="net.coderbee.warmhill.aop.AspectJAutoProxyCreator" /> <!-- 定义 pointcut --> <bean id="pointcut" class="net.coderbee.warmhill.aop.AspectJExpressionPointcut" > <property name="expression" value="execution(* net.coderbee..*.*(..))" /> </bean> <!-- 定义 任务 --> <bean id="timerInterceptor" class="net.coderbee.warmhill.aop.TimerInterceptor" /> <bean id="anotherInterceptor" class="net.coderbee.warmhill.aop.AnotherInterceptor" /> <!-- 定义 aspect --> <bean id="testAdvisor" class="net.coderbee.warmhill.aop.AspectJExpressionPointcutAdvisor"> <property name="advice" ref="timerInterceptor" /> <property name="pointcut" ref="pointcut" /> </bean> <bean id="testAdvisor2" class="net.coderbee.warmhill.aop.AspectJExpressionPointcutAdvisor"> <property name="advice" ref="anotherInterceptor" /> <property name="pointcut" ref="pointcut" /> </bean>
2. 任务实现
任务的实现类必须实现 org.aopalliance.intercept.MethodInterceptor
接口,至于是在目标关注之前还是之后执行由任务实现类自行决定。
下面是个计算目标方法调用耗时的任务实现:
public class TimerInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { long start = System.currentTimeMillis(); System.out.println("start invoke " + invocation.getMethod().getName()); Object result = invocation.proceed(); System.out.println("end invoke " + invocation.getMethod().getName() + " used time millils :" + (System.currentTimeMillis() - start)); return result; } }
3. 切入点实现
切入点只支持被调用方法,采用 aspectj 类库实现,用于匹配给定的 Class 是否满足该切入点。
具体实现见类: AspectJExpressionPointcut
。
4. 织入实现
warnhill
基于 IoC 容器的 BeanPostProcessor
机制对生成过程中的 bean 进行加工,织入相关的目标逻辑。
对于同一目标上的多个切面,是按声明的顺序生效的。对于代理机制,最后加入的代理反而是最先生效的。因此,对于多个切面,需要按声明的逆序进行切入,以便让调用时按声明顺序调用任务的逻辑。
对于框架基础设施类、任务类的实现是不能做织入的,避免循环地织入。
AspectJAutoProxyCreator
是 BeanPostProcessor
的一个实现类。下面是织入的核心:
public Object postProcessAfterInit(Object bean, String beanId) { if (Advice.class.isAssignableFrom(bean.getClass()) || Advisor.class.isAssignableFrom(bean.getClass()) || MethodInterceptor.class.isAssignableFrom(bean.getClass()) || Pointcut.class.isAssignableFrom(bean.getClass())) { return bean; } Class<?> beanClass = bean.getClass(); List<AspectJExpressionPointcutAdvisor> pointcutAdvisors = beanFactory.getBeans(AspectJExpressionPointcutAdvisor.class); Collections.reverse(pointcutAdvisors); for (AspectJExpressionPointcutAdvisor pointcutAdvisor : pointcutAdvisors) { if (pointcutAdvisor.getPointcut().getClassFilter().isMatch(beanClass)) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setMethodMatcher(pointcutAdvisor.getPointcut().getMethodMatcher()); proxyFactory.setInterceptor((MethodInterceptor) pointcutAdvisor.getAdvice()); TargetSource targetSource = new TargetSource(bean, beanClass, beanClass.getInterfaces()); proxyFactory.setTargetSource(targetSource); bean = proxyFactory.getProxy(); } } return bean; }
注意:上面的逻辑只是对 bean 的类型进行匹配,匹配则生成代理对象,对方法的判断是在调用时进行的。
CglibAopProxy
里面有对方法进行判断:
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { CglibMethodInvocation cglibMethodInvocation = new CglibMethodInvocation(method, advisorSupport .getTargetSource().getTarget(), objects, methodProxy); if (advisorSupport.getMethodMatcher() != null && advisorSupport.getMethodMatcher().matches(method, advisorSupport.getTargetSource().getTargetType())){ return advisorSupport.getInterceptor().invoke(cglibMethodInvocation); } return cglibMethodInvocation.proceed(); }
以上所述就是小编给大家介绍的《微热山丘,探索 IoC、AOP 实现原理(二) AOP 实现原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Docker实现原理之 - OverlayFS实现原理
- 带你了解vue计算属性的实现原理以及vuex的实现原理
- Docker原理之 - CGroup实现原理
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
- 移动端下拉刷新头实现原理及代码实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。