• spring---aop(5)---Spring AOP的配置的背后的配置


    写在前面

      Spring AOP中Pointcut,dvice 和 Advisor三个概念

      1)切入点 Pointcut

        在介绍Pointcut之前,有必要先介绍 Join Point(连接点)概念。

        连接点:程序运行中的某个阶段点,比如方法的调用、异常的抛出等。比如方法doSome();Pointcut是JoinPoint的集合,它是程序中需要注入Advice 的位置的集合,指明Advice要在什么样的条件下才能被触发。org.springframework.aop.Pointcut接口用来指定到特定的类和方法。

      2)通知Advice

        它是某个连接点所采用的处理逻辑,也就是向连接点注入的代码。例如:输出的日志信息 就是一个Advice。

      3)Advisor

        Advisor是Pointcut和Advice的配置器,它包括Pointcut和Advice,是将Advice注入程序中Pointcut位置的代码。

    <aop:aspectj-autoproxy/>
    <aop:config proxy-target-class="true">
           <aop:pointcut id="servicePointcut" expression="execution(* com.cpic..*Service.*(..))" />
           <aop:advisor pointcut-ref="servicePointcut" advice-ref="txAdvice" order="3" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
           <tx:attributes>
               <tx:method name="add*" />
           </tx:attributes>
    </tx:advice>

    接下来就需要看下配置完成之后是如何生成代理对象的

      还是要从对xml中的配置<aop:config>标签的解析来入手。同样是从标签解析接口开始,即找BeanDefinitionParser的实现类,最终我们会找到AspectJAutoProxyBeanDefinitionParser是用来处理aspectj-autoproxy标签的,而ConfigBeanDefinitionParser则是用来处理aop:config标签的。看下ConfigBeanDefinitionParser的解析过程: 

    public BeanDefinition parse(Element element, ParserContext parserContext) {
            CompositeComponentDefinition compositeDef =
                    new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
            parserContext.pushContainingComponent(compositeDef);
            configureAutoProxyCreator(parserContext, element);
            List<Element> childElts = DomUtils.getChildElements(element);
            for (Element elt: childElts) {
                String localName = parserContext.getDelegate().getLocalName(elt);
                if (POINTCUT.equals(localName)) {
                    parsePointcut(elt, parserContext);
                }
                else if (ADVISOR.equals(localName)) {
                    parseAdvisor(elt, parserContext);
                }
                else if (ASPECT.equals(localName)) {
                    parseAspect(elt, parserContext);
                }
            }
            parserContext.popAndRegisterContainingComponent();
            return null;
        }

      以上过程比较费劲,有兴趣的可以弄清楚。这里主要注册一些Advisor,同时注册了一个AspectJAwareAdvisorAutoProxyCreator,并且设置xml中所配置的proxy-target-class和expose-proxy到它的属性中。AspectJAwareAdvisorAutoProxyCreator本身存储着配置信息,然后使用这些配置创建出来代理对象,在它的父类AbstractAutoProxyCreator的createProxy方法中: 

    protected Object createProxy(
                Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
            ProxyFactory proxyFactory = new ProxyFactory();
            // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
            //重点1 proxyFactory.copyFrom(this);将ProxyConfig信息复制到ProxyFactory 中。ProxyFactory、AspectJAwareAdvisorAutoProxyCreator都继承了ProxyConfig,ProxyConfig拥有代理的一些配置信息。看下ProxyConfig: 
            proxyFactory.copyFrom(this);
            //重点2
            if (!proxyFactory.isProxyTargetClass()) {
                if (shouldProxyTargetClass(beanClass, beanName)) {
                    proxyFactory.setProxyTargetClass(true);
                }
                else {
                    evaluateProxyInterfaces(beanClass, proxyFactory);
                }
            }
            Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
            for (Advisor advisor : advisors) {
                proxyFactory.addAdvisor(advisor);
            }
            proxyFactory.setTargetSource(targetSource);
            customizeProxyFactory(proxyFactory);
            proxyFactory.setFrozen(this.freezeProxy);
            if (advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
            }
            //重点3
            return proxyFactory.getProxy(this.proxyClassLoader);
        }

    然后我们就详细的说明下整个过程: 
      重点1:proxyFactory.copyFrom(this);将ProxyConfig信息复制到ProxyFactory 中。ProxyFactory、AspectJAwareAdvisorAutoProxyCreator都继承了ProxyConfig,ProxyConfig拥有代理的一些配置信息。

      看下ProxyConfig: 

    public class ProxyConfig implements Serializable {
        //是否强制使用CGLIB 代理对象
        private boolean proxyTargetClass = false;
        //是否优化
        private boolean optimize = false;
        boolean opaque = false;
        //是否在线程内部暴露出代理对象
        boolean exposeProxy = false;
        private boolean frozen = false;
    }    

      

      重点2:复制完配置信息后,看下proxyTargetClass 属性是否为false,则查看目标类是否含有接口,若无则仍然设置proxyTargetClass为true,若有则把接口设置到ProxyFactory中。然后在设置些Advisor、targetSource等其他参数,为创建代理对象做准备。来看下上述Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);的具体内容: 

        protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
            // Handle prototypes correctly...
            Advisor[] commonInterceptors = resolveInterceptorNames();
            List<Object> allInterceptors = new ArrayList<Object>();
            if (specificInterceptors != null) {
                allInterceptors.addAll(Arrays.asList(specificInterceptors));
                if (commonInterceptors != null) {
                    if (this.applyCommonInterceptorsFirst) {
                        allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                    }
                    else {
                        allInterceptors.addAll(Arrays.asList(commonInterceptors));
                    }
                }
            }
            Advisor[] advisors = new Advisor[allInterceptors.size()];
            for (int i = 0; i < allInterceptors.size(); i++) {
                ////重点重点重点重点重点重点重点(对配置信息中的specificInterceptors全部封装成Advisor。再看下具体的封装过程,在上述wrap方法中 )
                advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
            }
            return advisors;
        }    

      具体的封装过程(如果是Advisor直接返回不处理,接下来必须是Advice,然后通过MethodInterceptor和AdvisorAdapter 对Advice进行包装。)

        @Override
        public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
            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);
                }
            }
            throw new UnknownAdviceTypeException(advice);
        }

      重点3:使用DefaultAopProxyFactory来创建AopProxy,有了AopProxy我们就能创建代理对象了。看下AopProxy的创建过程: 

    @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    throw new AopConfigException("TargetSource cannot determine target class: " +
                            "Either an interface or a target is required for proxy creation.");
                }
                if (targetClass.isInterface()) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }

    这里决定着到底采用jdk动态代理还是cglib方式来创建代理对象。 
      条件1:config.isOptimize()是否进行优化,默认是false。 

      条件2:config.isProxyTargetClass()就是ProxyConfig的proxyTargetClass属性,是否强制使用cglib代理。但它为true也不是肯定就采用cglib,因为下面还有一个判断条件,即目标类是接口,则使用jdk动态代理的方式。

      条件3:hasNoUserSuppliedProxyInterfaces(config)目标类没有实现接口,或者有但是是接口类型是SpringProxy

      只要上述三个条件有一个为true并且目标类不是接口就会采用cglib方式来创建代理对象,其他情况使用jdk动态代理的方式来创建。

      有了JdkDynamicAopProxy和ObjenesisCglibAopProxy则可以顺利创建出代理对象,便可以跳到这篇文章http://www.cnblogs.com/chihirotan/p/7063781.html,至此整个过程就连接通了。

    总结 

    我们先看下ProxyFactory是什么东西。 把下面的图理解透了,就掌握了SpringAOP的整个运行机制

  • 相关阅读:
    数据库备份 DBS(Database Backup),知识点
    关系型数据库 RDS(Relational Database Service),知识点
    对象存储服务 OSS(Object Storage Service),知识点(待补充上仓库代码)
    Java 为什么需要包装类,如何使用包装类?
    for each 语句
    缓存中,2个注解:@cacheable 与 @cacheput 的区别
    微信小程序,相关代码
    微信小程序中的事件
    通俗易懂:索引、单列索引、复合索引、主键、唯一索引、聚簇索引、非聚簇索引、唯一聚簇索引 的区别与联系
    MySQL 的各种 join
  • 原文地址:https://www.cnblogs.com/chihirotan/p/7346644.html
Copyright © 2020-2023  润新知