欢迎来到飞鸟慕鱼博客,开始您的技术之旅!
当前位置: 首页知识笔记正文

spring aop:advisor,spring aop简单例子

墨初 知识笔记 114阅读

上一章我们知道Spring开启AOP之后会注册AnnotationAwareAspectJAutoProxyCreator类的定义信息所以在属性注入之后initializeBean的applyBeanPostProcessorsAfterInitialization方法执行的时候调用AnnotationAwareAspectJAutoProxyCreator父类(AbstractAutoProxyCreator)的postProcessAfterInitialization方法来创建AOP的代理。

// AbstractAutoProxyCreator类Overridepublic Object postProcessAfterInitialization(Nullable Object bean, String beanName) {if (bean ! null) {Object cacheKey  getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) ! bean) {// 真正进行处理的地方里面有代码很明显是用来创建代理对象的return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}

然后我们创建一个Aspect方便我们这章的分析

ComponentAspectpublic class ThamNotVeryUsefulAspect {Pointcut(execution(* com.qhyu.cloud.aop.service.QhyuAspectService.*(..))) // the pointcut expressionprivate void thamAnyOldTransfer() {} // the pointcut signatureBefore(thamAnyOldTransfer())public void before(){System.out.println(tham Before 方法调用前);}After(thamAnyOldTransfer())public void after(){System.out.println(tham After 方法调用前);}AfterReturning(thamAnyOldTransfer())public void afterReturning(){System.out.println(tham afterReturning);}AfterThrowing(thamAnyOldTransfer())public void afterThrowing(){System.out.println(tham AfterThrowing);}Around(thamAnyOldTransfer())public Object  around(ProceedingJoinPoint pjp) throws Throwable{// start stopwatchSystem.out.println(tham around before);Object retVal  pjp.proceed();// stop stopwatchSystem.out.println(tham around after);return retVal;}}

放一张整体的流程图方便我们查看知通构建的整体流程。

wrapIfNecessary方法的实现流程

1、首先判断bean是否需要被代理如果不需要直接返回原始bean实例 。

2、如果需要代理则获取bean所有的advisor并根据advisor的pointcout对bean进行匹配得到所有需要拦截的方法 。

3、根据bean的类型和配置信息决定使用哪种类型的代理对象CGLIB或者JDK动态代理 。

4、将advisor和代理对象绑定并将代理对象返回。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// targetSource是干嘛得if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// advisedBeans不会进行代理if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}// 什么情况会shouldSkip提前解析切面if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.Object[] specificInterceptors  getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors ! DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);// 创建代理对象Object proxy  createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
findCandidateAdvisors获取候选的Advisors

获取候选的Advisors是使用的子类(AnnotationAwareAspectJAutoProxuCreator)的实现然后我们的基于注解的Aspect(ThamNotVeryUsefulAspect)会执行this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来添加

Overrideprotected List<Advisor> findCandidateAdvisors() {// Add all the Spring advisors found according to superclass rules.List<Advisor> advisors  super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.if (this.aspectJAdvisorsBuilder ! null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;}
构建AspectJ的Advisors

首先在BeanFactoryAspectJAdvisorsBuilder的this.advisorFactory.getAdvisors(factory)打个断点

然后我断点进来之后我就发现了这个其实是有顺序的也就是说明在这个内部实现了第一次排序。

第一次排序

接下来会进入ReflectiveAspectJAdvisorFactory的getAdvisors方法。其中核心就是for循环中的getAdvisorMethods方法。

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass  aspectInstanceFactory.getAspectMetadata().getAspectClass();String aspectName  aspectInstanceFactory.getAspectMetadata().getAspectName();validate(aspectClass);// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator// so that it will only instantiate once.MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors  new ArrayList<>();//遍历切面方法,这里会把标注了Pointcut 注解的排除掉只剩下通知注解如Before,Afterfor (Method method : getAdvisorMethods(aspectClass)) {Advisor advisor  getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);if (advisor ! null) {advisors.add(advisor);}}// If its a per target aspect, emit the dummy instantiating aspect.if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor  new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// Find introduction fields.for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor  getDeclareParentsAdvisor(field);if (advisor ! null) {advisors.add(advisor);}}return advisors;}// 遍历切面方法时进行排序可以理解为第一次排序private List<Method> getAdvisorMethods(Class<?> aspectClass) {List<Method> methods  new ArrayList<>();ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);if (methods.size() > 1) {methods.sort(adviceMethodComparator);}return methods;}

首先会排除PointCut的方法

private static final MethodFilter adviceMethodFilter  ReflectionUtils.USER_DECLARED_METHODS.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class)  null));

然后创建了一个比较器

private static final Comparator<Method> adviceMethodComparator;static {// Note: although After is ordered before AfterReturning and AfterThrowing,// an After advice method will actually be invoked after AfterReturning and// AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)// invokes proceed() in a try block and only invokes the After advice method// in a corresponding finally block.Comparator<Method> adviceKindComparator  new ConvertingComparator<>(new InstanceComparator<>(Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),(Converter<Method, Annotation>) method -> {AspectJAnnotation<?> ">">  AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);return (">"> ! null ? ">">.getAnnotation() : null);});Comparator<Method> methodNameComparator  new ConvertingComparator<>(Method::getName);adviceMethodComparator  adviceKindComparator.thenComparing(methodNameComparator);}

很明显是按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的顺序进行顺序的构建。

第二次排序

根据AbstractAdvisorAutoProxyCreator的findEligibleAdvisors的代码可知第一次排序发生在findCandidateAdvisors方法。第二次排序则发生在次方法中的sortAdvisors。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {List<Advisor> candidateAdvisors  findCandidateAdvisors();// Around before after afterReturing afterThrowingList<Advisor> eligibleAdvisors  findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {// 这里是通过order进行排序的eligibleAdvisors  sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}

第一次排序是对一个Aspect中的所有advice进行排序第二次排序是对Aspect进行排序可以通过实现Order接口或者Order注解来设置顺序如果没有实现order的话是以加载的顺序来的。一般情况下加载的顺序可能不可控所以如果有必要的话需要实现order。

创建两个Aspect然后都没有实现Order

顺序是ThamNotVersyUsefulAspect在NotVeryUsefulAspect之前

但是如果我们把两个放一起这个时候NotVeryUsefulAspect先加载就会在前面。

如果我们设置ThamNotVeryUsefulAspect的Order(98),NotVeryUsefulAspect的Order(99),Order小的将排在前面。

ComponentAspectOrder(99)public class NotVeryUsefulAspect {}ComponentAspectOrder(98)public class ThamNotVeryUsefulAspect {}
写在最后

本章主要描述构建通知的顺序正在的执行过程将在下一章节进行分析。

标签:
声明:无特别说明,转载请标明本文来源!