Spring实现Aop有几种方法或者说实现增强有几种方法
1、不妨从Bean生成后是否会有代理生成入口:
exposedObject = initializeBean(beanName, exposedObject, mbd);
定位到方法最后
if (mbd == null || !mbd.isSynthetic()) { //这个地方可能生出代理实例,是aop的入口 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
显然这是beanPostProcessor接口的运用,代理是否会生成,需要看这个类,而这个类也是一个父类,具体实现是子类完成的,是这个类:
AnnotationAwareAspecjAutoproxyCreator(背下来的),我们继续向下走
2、寻找增强:
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
3、寻找切面:
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
4、找@Aspectj注解的类
List<Advisor> candidateAdvisors = findCandidateAdvisors();
5、进入findCandidateAdvisors() 时就是进入了刚才说的那个子类中,然后看到
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
这两个方法都有对增强方法的收集,其主要原理就是先收集,再匹配,匹配成功的增强才真的是增强。
这里只看关键代码,先看super这个方法做了什么事情。
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames;
很明显是根据 Advisor.class 类型进行的类查找,也就是说这个类型的类会是一种增强,实际情况是实现了这个接口的类。
找到名称后,实例化
advisors.add(this.beanFactory.getBean(name, Advisor.class));
这就是第一种增强了。
6、看下面的build方法,也是看关键代码
//创建切面advisor对象 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
这个代码有点深,我直接说做了什么事情,在有@Aspectj注解的类中,找所有的方法,特点是没有@PointCut注解,并且有其他增强注解,找到后
连同pointcut表达式对象一起封装成Advisor对象,也就是增强。然后返回。
这就是第二种增强了。
3、后续还有一些匹配过滤,暂时不看,直接回到最开始这里
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); //如果有切面,则生成该bean的代理 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //把被代理对象bean实例封装到SingletonTargetSource对象中 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; }
进入createProxy方法中的Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 方法
第一行就是一个关键点 Advisor[] commonInterceptors = resolveInterceptorNames(); 进入看看
for (String beanName : this.interceptorNames) { if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) { Assert.state(bf != null, "BeanFactory required for resolving interceptor names"); Object next = bf.getBean(beanName); advisors.add(this.advisorAdapterRegistry.wrap(next)); } }
倘若 this.interceptorNames 有内容的话,那么这个类也是会被增强的,那么内容的形式很关键,具体什么形式才符合呢
this.advisorAdapterRegistry.wrap(next) 这个代码给出了答案:
if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } }
要么这个类是 Advisor 类型,要么是 MethodInterceptor 类型,要么是 adapters中的某个类型,看下这个集合中是什么吧
public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); }
注册了三种类型的对象,其实相当于在for循环外面又加了几种类型而已。
还有一个关键点就是 DefaultPointcutAdvisor 对象,它有一个特点就是拦截所有方法,厉害吧。光这个地方就有5中增强,当然这里面的第一种可以不算,也就是4种。
加上最开始说的那两种,应该是有6中方法实现方法的增强。这里可能大家还有一个疑问就是,this.interceptorNames 值是哪来的,这里具体不跟了,是通过这种方式
拿到AnnotationAwareAspectJAutoProxyCreator对象调用setInterceptorNames 设置的,可以通过实现BeandefinationRigistryPostProcessor拿到具体bean然后set,熟悉spring的
都知道怎么做,但是有一点需要注意,就是时序问题,如果加入数组的时机晚于bean实例化,比如此bean被别的bean依赖注入了,放入了缓存,但是此时放入数组的操作还没进行,这就有问题了。
总结一下:
第一种:实现Advisor接口,典型代表注解事务(@Transanctional的实现原理)
第二种:@Aspectj注解类加增强方法
第三种:添加interceptor数组值,并且值要是 MethodInterceptor类型
第四种:添加interceptor数组值,并且值要是 MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter 类型。