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


  • 相关阅读:
    《不懂说话你怎么带团队》读书笔记
    Java内存模型与指令重排
    线程的基本操作
    Spring MVC核心技术
    Spring MVC注解式开发
    Spring MVC执行流程
    大厂技术博客汇总
    内嵌tomcat启动速度慢
    Java 对IP请求进行限流.
    Java过滤XSS脚本, 可通过Appscan扫描
  • 原文地址:https://www.cnblogs.com/zxg-blog/p/15080764.html
Copyright © 2020-2023  润新知