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 类型。


posted @ 2021-07-30 17:42  0o飞行天下o0  阅读(229)  评论(0编辑  收藏  举报