zoukankan      html  css  js  c++  java
  • Spring IOC及AOP学习总结

    一、Spring IOC体系学习总结:

    Spring中有两个容器体系,一类是BeanFactory、还有一类是ApplicationContext。BeanFactory提供了基础的容器功能。ApplicationContext则是基于BeanFactory建立的一套更加丰富的容器体系,基于ApplicationContext构建了Spring AOP体系(基于AOP体系又构建了声明式事务模型),I18n的支持,基于观察者模式的事件模型,多渠道的Bean资源的加载(比方从文件系统,从internet)。以下看一下两个容器体系的类结构图。
    BeanFactory容器体系结构图:

    如上图:BeanFactory接口定义了IOC容器的最主要的方法,比如getBean,isSingleton等。子类ListableBeanFactory则是补充定义了批量获取Bean信息的一些列表方法,好多方法返回的都是数据或者列表,比方获取全部的Bean的名字等。

    而子类HierarchialBeanFactory则是描写叙述了IOC容器的双亲模型,是IOC容器具备了管理双亲容器的功能。比如加入了getParentBeanFactory的功能(这里展开一下,在获取Bean的时候。是先在父容器中去获取,假设获取不到,才会在本身的容器中获取)。

    最后ConfigurableBeanFactory定义了IOC容器的一些配置功能。比如加入了setParentBeanFactory方法。addBeanPostProcessor配置Bean后置处理器的方法等。通过观察继承体系能够看出。DefaultListableBeanFactory辗转反側的继承了全部的接口,由此可见DefaultListableBeanFactory是比較土豪的,是在BeanFactory容器体系下比較完好的容器模型。
    (1) 看下直接通过编程式使用 BeanFactory的一个样例,顺便分析一下:

    ClassPathResource res = new ClassPathResource("beans.xml");
    //直接使用DefaultListableBeanFactory
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(res);
    

    上述代码相应了BeanFactory载入beans.xml的过程。详细相应到Spring的载入过程为:

    调用DefaultListBeanFactory的registerBeanDefinition方法的代码为:

    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    

    能够看到传入的參数有两个 一个是bdHolder这个相应的事实上就是BeanDefinition的包装。另外一个就是BeanDefinitionRegistry对象。

    而这个BeanDefinitionRegistry对象的实例就是DefaultListBeanFactory。參考例如以下继承关系:


    所以事实上调用就是 DefaultListBeanFactory 的 registerBeanDefinition 方法:

    /**
     * 向BeanFactory的map容器中注冊Bean
     */
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
    
        synchronized (this.beanDefinitionMap) {
            Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
                //当不同意新的Bean覆盖老的Bean时,则会抛异常出来
                if (!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }
                else {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
            }
            else {
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
    
            resetBeanDefinition(beanName);
        }
    }
    

    支持BeanDefinition的信息都被注冊到了DefaultListBeanFactory中。

    (2) 以上看到了BeanDefinition注冊到DefaultListBeanFactory的过程,当中BeanDefinition事实上就相应了我们xml文件里配置的Bean的信息,BeanDefinition信息注冊到DefaultListBeanFactory中事实上并没有完毕对Bean的实例化,注冊的仅仅是Bean实例的元数据信息。即还没有完毕Bean依赖的关系的注入。首先看下BeanDefinition的类的继承体系:

    这个图就看看得了,不具体分析了。

    以下再看下Xml配置文件中的Bean是怎样变成BeanDefinition的:

    BeanDefinitionParserDelegate封装了解析Xml文件的一些方法,主要有这个Delegate将Xml文件解析成BeanDefinition。

    (3) 上面看到了BeanDefinition的解析以及注冊到BeanFactory的过程。

    然后就是针对BeanDefinition的完毕Bean依赖关系的注入过程。

    获取一个Bean的实例并完毕注入的步骤例如以下:


    当中 AbstractAutowireCapableBeanFactory 的 populateBean 是实际发生Bean依赖注入的地方。

    详细的代码例如以下:

    //实际涉及到bean注入的方法
    protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
        PropertyValues pvs = mbd.getPropertyValues();
    
        if (bw == null) {
            if (!pvs.isEmpty()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }
    
        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;
    
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }
    
        if (!continueWithPropertyPopulation) {
            return;
        }
    
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    
            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
    
            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
    
            pvs = newPvs;
        }
    
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    
        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            //检查Bean的依赖是否已经装配好
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }
        //对属性进行依赖注入
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
    

    (4) Spring的还有一种高级的容器ApplicationContext在BeanFactory的基础上加入了很多其它的面向框架的功能,比方和AOP的融合,生命周期的管理。Bean处理器(BeanProcessor)加入等,上面已经说了。就不提了。下文看下ApplicationContext的类继承关系图:

    简述:ApplicationContext 的子类主要包括两个方面:ConfigurableApplicationContext 表示该 Context 是可改动的,也就是在构建 Context 中用户能够动态加入或改动已有的配置信息,它以下又有多个子类,当中最常常使用的是可更新的 Context,即:AbstractRefreshableApplicationContext 类。 WebApplicationContext 顾名思义。就是为 web 准备的 Context 他能够直接訪问到 ServletContext。通常情况下。这个接口使用的少。 再往下分就是依照构建 Context 的文件类型,接着就是訪问 Context 的方式。

    这样一级一级构成了完整的 Context 等级层次。

    整体来说 ApplicationContext 必需要完毕下面几件事:
    I.标识一个应用环境
    II.利用 BeanFactory 创建 Bean 对象
    III.保存对象关系表
    IV.可以捕获各种事件
    V.Context 作为 Spring 的 Ioc 容器。基本上整合了 Spring 的大部分功能,或者说是大部分功能的基础。

    ApplicationContext和BeanFactory及ResourceLoader的关系例如以下图:


    ApplicationContext继承了ResourceLoader。注定了ApplicationContext能够完毕多渠道外部资源的读入,不光是能够载入配置的xml文件。还有上图也清晰的标识了ApplicationContext和BeanFactory的关系。

    ApplicationContext容器初始化的过程还是能够看上面那个时序图:


    AbstractApplicationContext的容器初始化过程是通过调用Refresh方法完毕的,详细方法的代码例如以下:

    //整个容器启动的入口
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();
    
            // Tell the subclass to refresh the internal bean factory.
            // 在子类中启动RefreshBeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);
    
            try {
                // Allows post-processing of the bean factory in context subclasses.
                //设置post的后置处理
                postProcessBeanFactory(beanFactory);
    
                // Invoke factory processors registered as beans in the context.
                //调用Bean的后置处理器,后置处理器是在Bean定义时向容器注冊的
                invokeBeanFactoryPostProcessors(beanFactory);
    
                // Register bean processors that intercept bean creation.
                //注冊Bean的后置处理器,在Bean创建过程中调用
                registerBeanPostProcessors(beanFactory);
    
                // Initialize message source for this context.
                //对上下文的消息源进行初始化
                initMessageSource();
    
                // Initialize event multicaster for this context.
                //初始化上下文的事件机制
                initApplicationEventMulticaster();
    
                // Initialize other special beans in specific context subclasses.
                //初始化其它的特殊Bean
                onRefresh();
    
                // Check for listener beans and register them.
                //检查监听Bean并将这些Bean向容器注冊
                registerListeners();
    
                // Instantiate all remaining (non-lazy-init) singletons.
                //实例化全部的(non-lazy-init)单件
                finishBeanFactoryInitialization(beanFactory);
    
                // Last step: publish corresponding event.
                //公布容器事件,结束Refresh进程
                finishRefresh();
            }
    
            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();
    
                // Reset 'active' flag.
                cancelRefresh(ex);
    
                // Propagate exception to caller.
                throw ex;
            }
        }
    

    上面的代码中。每一步干什么都写了凝视。

    以下再补充扩展一下ResourceLoader和Resource的类体系结构图:
    ResourceLoader的类体系结构图:


    Resource的类体系结构图:

    Resource抽象出了资源的概念。这里的资源就能够理解为Spring容器须要载入的Bean的元数据。ApplicationContext继承了ResourceLoader。使其具备了载入元数据资源的能力。


    最后再附上一张BeanFactory和ApplicationContext比較完毕的类体系结构图:

    (5) IOC容器大体的结构就说这么多。以下总结一下几个常见的问题:

    Spring中的FactoryBean怎么理解:
    Spring中有两种类型的Bean:一种是普通的javaBean。还有一种就是工厂Bean(FactoryBean),这两种Bean对IOC容器BeanFactory来说在获取Bean的方式上有一些细微的区别。看个实例DEMO:

    public class MyFactoryBean implements FactoryBean<Date>,BeanNameAware {
    
    private String name;
    
    @Override
    public void setBeanName(String name) {
        this.name = name;
    }
    
    @Override
    public Date getObject() throws Exception {
        return new Date();
    }
    
    @Override
    public Class<?

    > getObjectType() { return Date.class; } @Override public boolean isSingleton() { return false; } public void sayName() { System.out.println("My name is "+this.name); } public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); Resource resource = new ClassPathResource("/aop/demo/demo4/applicationContext.xml"); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.loadBeanDefinitions(resource); //这里获取的事实上是自己定义FactoryBean中getObject获取到的Value Date now = (Date) beanFactory.getBean("myFactoryBean"); System.out.println(now); //这里获取的是FactoryBean MyFactoryBean factoryBean = (MyFactoryBean) beanFactory.getBean("&myFactoryBean"); factoryBean.sayName(); } }

    运行的输出结果:

    Thu May 08 09:46:43 CST 2014
    My name is myFactoryBean
    

    看代码,从BeanFactory中获取 myFactoryBean的过程中依据两种名字进行获取 分别为 myFactoryBean,&myFactoryBean,通过myFactoryBean获取到的Bean假设实现了Spring定义的FactoryBean的接口。那么将会调用该接口的getObject方法,获取真是的值。假设&myFactoryBean来获取Bean的话就直接返回 FactoryBean实例。FactoryBean这个类型的Bean事实上是Spring为我们提供的一个扩展点。我们能够自行定义FactoryBean。然后对容器中真实的对象做一些包装处理,比如为了实现Spring AOP,则定义了 ProxyFactoryBean,在调用器getObject方法时。对目标对象进行了动态代理。将横切逻辑编织到目标对象的方法逻辑中,详细分析下文有讲述。


    BeanFactory 和 ApplicationContext 在获取Bean方式上的差别?

    BeanFactory在获取Bean的时候,是延迟加载的,既不会完毕BeanDefinition的加载。也不会完毕Bean的依赖注入,xml文件即使配置错了也不会检查出来,它是在获取的时候才完毕了Bean的关联关系的注入的。而ApplicationContext则是在容器启动时直接调用器Refresh方法,完毕整个配置文件描写叙述的Bean的加载,可是并没有完毕依赖的注入,当第一次调用getBean方法获取Bean的时候,假设Bean是单例的会完毕Bean依赖关系的注入,而且缓存。假设Bean是多例的。则每次都会create一个新Bean,并完毕这个Bean依赖注入。

    二、Spring AOP体系学习总结:

    要理解AOP总体的逻辑须要理解一下Advice,Pointcut,Advisor的概念以及他们的关系。


    Advice是为Spring Bean提供增强逻辑的接口,提供了多种方法增强的方式,比方前置,后置,包裹等增强方式。看下Advice的类体系结构图:

    图中定义了主要有3中类型的Advice,各自是BeforeAdvice,AfterAdvice 和 Interceptor,BeforeAdvice就是定义的就是方法的前置织入逻辑。AfterAdvice就是方法的后置织入逻辑。MethodInteceptor定义的是方法的包裹逻辑。想要分析其原理。先要看看怎么用,看一个应用的DEMO:

    AfterAdvice.class:
    public class AfterAdvice implements AfterReturningAdvice {
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2,
                Object arg3) throws Throwable {
            System.out.println("这个是 AfterReturning 方法!");
        }
    }
    
    BeforeAdvice.class:
    public class BeforeAdvice implements MethodBeforeAdvice {
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2)
                throws Throwable {
            System.out.println("这是BeforeAdvice的before方法!");
        }
    }
    
    CompareInterceptor.class
    public class CompareInterceptor implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
              Object result = null;
              String stu_name = invocation.getArguments()[0].toString();
              if ( stu_name.equals("dragon")){
                  //假设学生是dragon时,运行目标方法,
                  result= invocation.proceed();            
              } else{
                  System.out.println("此学生是"+stu_name+"而不是dragon,不批准其增加.");
              }
              return result;
        }
    }
    

    以上定义的各自是目标方法的前置逻辑,后置逻辑,及包裹逻辑。

    目标类接口:
    public interface IStudent {
        public void addStudent(String name);
    }
    
    目标实现类:
    public class StudentImpl implements IStudent {
        @Override
        public void addStudent(String name) {
            System.out.println(name);
        }
    }
    

    Bean定义的配置文件:

    <beans>
     <bean id="beforeAdvice" class="aop.demo.demo1.BeforeAdvice"></bean>
     <bean id="afterAdvice" class="aop.demo.demo1.AfterAdvice"></bean>
     <bean id="compareInterceptor" class="aop.demo.demo1.CompareInterceptor"></bean>
     <bean id="studenttarget" class="aop.demo.demo1.StudentImpl"></bean>
     <bean id="student" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>aop.demo.demo1.IStudent</value>
        </property>
        <property name="interceptorNames">
        <list>
           <value>beforeAdvice</value>
           <value>afterAdvice</value>
           <value>compareInterceptor</value>  
        </list>
        </property>
        <property name="target">
            <ref bean="studenttarget"/>
        </property>
      </bean>
    </beans>
    
    測试驱动类:<br>
    public class DriverTest {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ApplicationContext ctx = new FileSystemXmlApplicationContext("/src/main/java/aop/demo/applicationContext.xml");
            IStudent person = (IStudent)ctx.getBean("student");
            //person.addStudent("dragon");
            person.addStudent("javadragon");
        }
    }
    
    //运行结果:<br>
    这是BeforeAdvice的before方法!

    此学生是javadragon而不是dragon,不批准其增加. 这个是 AfterReturning 方法!

    从上面的DEMO能够看到一共配置了 2个Advice和 1个Interceptor,然后这些配置都是作为 ProxyFactoryBean的属性存在的。上文中已经提到FactgoryBean概念。容器在获取ProxyFactoryBean的时候事实上是调用其 getObject方法。正式这个调用完毕了代理逻辑的编织。先看下这个ProxyFactoryBean getObjec方法的代码。


    public Object getObject() throws BeansException {
        //初始化通知器链
        initializeAdvisorChain();
        if (isSingleton()) {
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }
    
    private synchronized Object newPrototypeInstance() {
        // In the case of a prototype, we need to give the proxy
        // an independent instance of the configuration.
        // In this case, no proxy will have an instance of this object's configuration,
        // but will have an independent copy.
        if (logger.isTraceEnabled()) {
            logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
        }
    
        ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
        // The copy needs a fresh advisor chain, and a fresh TargetSource.
        TargetSource targetSource = freshTargetSource();
        copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
            // Rely on AOP infrastructure to tell us what interfaces to proxy.
            copy.setInterfaces(
                    ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
        }
        copy.setFrozen(this.freezeProxy);
    
        if (logger.isTraceEnabled()) {
            logger.trace("Using ProxyCreatorSupport copy: " + copy);
        }
        return getProxy(copy.createAopProxy());
    }
    

    以上两个方法就是ProxyFactoryBean获代替理对象的入口方法。详细的获取流程以下时序图表述一下:
    通过以上时序图能够看到,详细代理类的生成是有 JDKDynamicAopProxy 和 CglibProxy来完毕的。

    详细使用哪种动态代理的生成方式是依据目标类是否有接口 isInterface来推断的。相应DefaultAOPProxyFactory 生成代理类的方法例如以下:

    //这里有两个分支选择。一个是选择JDK的Proxy动态代理的实现。一个使用Cglib的实现。

    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); } if (!cglibAvailable) { throw new AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } //假设不是接口类要生成Proxy,那么使用CGLIB来生成 return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }

    由上文可知Advice是定义的Bean的前后的织入逻辑,那么这个织入逻辑是什么时候融入到方法中的呢。那就须要详细分析一下JDKDynamicAopProxy和Cglib2AopProxy了。
    先上两张张AopProxy的类图:


    AopProxy的依赖类图:

    由上图可见AopProxy是间接仅仅用了Advice来完毕Bean的编织强化操作,详细代码例如以下:

    JdkDynamicAopProxy的invoke方法:
    /**
     * Implementation of <code>InvocationHandler.invoke</code>.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
    
        TargetSource targetSource = this.advised.targetSource;
        Class targetClass = null;
        Object target = null;
    
        try {
            //假设目标对象没有实现Object类的基本方法:equals
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            //假设目标对象没有实现Object类的基本方法:hashCode
            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
    
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                //依据代理对象的配置来调用服务
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
    
            Object retVal;
    
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
    
            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
    
            // Get the interception chain for this method.
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            //假设未定义拦截器,那么就直接调用target相应的方法
            if (chain.isEmpty()) {
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }
            else {
                //假设有拦截器设定,那么须要调用拦截器之后才调用目标对象的相应方法。
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }
    
            // Massage return value if necessary.
            if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
    

    JdkDynamicAopProxy实现了JDK定义的 InvocationHandler接口,在实现JDK的动态代理的时候时间自身传入代理逻辑完毕Bean的强化。这个invoke方法就是强化Bean逻辑的核心。从代码中能够看到在详细运行被代理类的目标方法的时候,先是获取了一个连接器链:

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 
    

    然后再运行详细方法的时候。先会递归的调用拦截器的逻辑,我们定义的Advice逻辑和Interceptor逻辑就是封装在这些Interceptor里面的。拦截器链的调用织如逻辑能够看下ReflectiveMethodInvocation 这个类的 proceed方法:

    //递归调用拦截器链
    //无论是JdkDynamicAopProxy还是Cglib2Aop都是要用的这种方法运行的拦截器链
    public Object proceed() throws Throwable {
        //  We start with an index of -1 and increment early.
        // 从索引-1的拦截器開始调用。并按序递增。假设拦截器链中的拦截器迭代调用完毕,这里開始调用target的函数,这个函数是通过反射机制完毕的。
        // 详细实如今AopUtil.invokeJoinpointUsingReflection方法中。
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //这步才真正的调用目标方法
            return invokeJoinpoint();
        }
    
        Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                //这个里面也会运行Proceed方法完毕,Advice行为的调用
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    

    这种方法完毕了我们定义的拦截器的递归调用。详细能够看代码上的凝视。至于Cglib2AopProxy的拦截方式和JDkDynamicAopProxy能够说是如出一辙的,Cglib2AopProxy的强化逻辑能够看其内部类DynamicAdvisedInterceptor定义的intercept方法:

    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
    
        private AdvisedSupport advised;
    
        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }
    
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Class targetClass = null;
            Object target = null;
            try {
                if (this.advised.exposeProxy) {
                    // Make invocation available if necessary.
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                // May be <code>null</code>. Get as late as possible to minimize the time we
                // "own" the target, in case it comes from a pool.
                target = getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                // Check whether we only have one InvokerInterceptor: that is,
                // no real advice, but just reflective invocation of the target.
                //假设没有拦截器则直接调用目标方法
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    // We can skip creating a MethodInvocation: just invoke the target directly.
                    // Note that the final invoker must be an InvokerInterceptor, so we know
                    // it does nothing but a reflective operation on the target, and no hot
                    // swapping or fancy proxying.
                    retVal = methodProxy.invoke(target, args);
                }
                else {
                    // We need to create a method invocation...
                    // 假设拦截器有设置则对其进行拦截
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null) {
                    releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
    

    而这里定义的MethodInvocation相应的proceed方法和JDKDynamicAopProxy相应的同一个proceed方法。

    至此Spring 容器中Bean的强化逻辑就看完了。细心的同学可能会发现一个问题就是上面那个DEMO里,为什么把Advice配置在了Interceptor的属性里呢?:

     <property name="interceptorNames">
        <list>
           <value>beforeAdvice</value>
           <value>afterAdvice</value>
           <value>compareInterceptor</value>  
        </list>
    </property>
    

    这种配置无非是把Advice当做了拦截器注入,事实上这里面还存在一个适配器的概念:
     是这些Adapter将我们定义的Advice转换成了Interceptor,然后再代理类目完毕拦截调用,看个源代码:
    MethodBeforeAdviceAdapter的适配转换实现:

    /**
     * Adapter to enable {@link org.springframework.aop.MethodBeforeAdvice}
     * to be used in the Spring AOP framework.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     */
    class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    
        public boolean supportsAdvice(Advice advice) {
            return (advice instanceof MethodBeforeAdvice);
        }
    
        public MethodInterceptor getInterceptor(Advisor advisor) {
            MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
            return new MethodBeforeAdviceInterceptor(advice);
        }
    }
    

    正是这些适配器完毕了我们定义的Advice和Inteceptor的转换。

    由此可见Advice和Interceptor有着非常强的血缘关系,以下看个Advice和Inteceptor的关系图:

    Advice就讲到这吧,以下看下Pointcut的概念:
    Pointcut(切点)决定Advice应该作用于哪个连接点,也就说通过Pointcut来定义须要增强的方法集合,这些集合的选取能够依照一定的规则来完毕,说白了就是制定那些方法须要增强。以下是Pointcut的类继承体系结构:

    Pointcut不想多说,看个实际使用的配置文件的样例:

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="     
          http://www.springframework.org/schema/beans     
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
          http://www.springframework.org/schema/context     
          http://www.springframework.org/schema/context/spring-context-3.0.xsd 
          http://www.springframework.org/schema/aop     
          http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    default-autowire="byName">
    
    <!-- ==============================利用spring自己的aop配置================================ -->
    <!-- 声明一个业务类 -->
    <bean id="baseBusiness" class="aop.demo.demo2.BaseBusiness" />
    
    <!-- 声明通知类 -->
    <bean id="baseBefore" class="aop.demo.demo2.BaseBeforeAdvice" />
    <bean id="baseAfterReturn" class="aop.demo.demo2.BaseAfterReturnAdvice" />
    <bean id="baseAfterThrows" class="aop.demo.demo2.BaseAfterThrowsAdvice" />
    <bean id="baseAround" class="aop.demo.demo2.BaseAroundAdvice" />
    
    <!-- 指定切点匹配类 -->
    <bean id="pointcut" class="aop.demo.demo2.Pointcut" />
    
    <!-- 包装通知,指定切点 -->
    <bean id="matchBeforeAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="pointcut">
            <ref bean="pointcut" />
        </property>
        <property name="advice">
            <ref bean="baseBefore" />
        </property>
    </bean>
    
    <!-- 使用ProxyFactoryBean 产生代理对象 -->
    <bean id="businessProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 代理对象所实现的接口 ,假设有接口能够这样设置 -->
        <property name="proxyInterfaces">
            <value>aop.demo.demo2.IBaseBusiness</value>
        </property>
    
        <!-- 设置目标对象 -->
        <property name="target">
            <ref local="baseBusiness" />
        </property>
        <!-- 代理对象所使用的拦截器 -->
        <property name="interceptorNames">
            <list>
                <!-- 这个Advisor之所以能够设置在这里。是由于会有AdvisorAdapter做转换适配 -->
                <value>matchBeforeAdvisor</value>
                <value>baseAfterReturn</value>
                <value>baseAround</value>
            </list>
        </property>
    </bean>
    </beans>
    

    通过配置文件能够看出来通过Advisor将 pointcut和Advice整合在了一起。然后将这些Advisor注入到ProxyFactoryBean的体系中。这样这个Advisor就变成了有条件的链接器,pointcut就是条件。Advice就是相应的运行逻辑,而Advisor就是整合这两个实体的一个关联关系。


    以上学习的代码版本号是: 代码版本号是Spring V3.1.1 svn地址是:https://github.com/lantian0802/spring-framework.git/tags/v3.1.1.RELEASE

  • 相关阅读:
    PAT A1094 The Largest Generation (25 分)——树的bfs遍历
    PAT A1055 The World's Richest (25 分)——排序
    PAT A1052 Linked List Sorting (25 分)——链表,排序
    PAT A1076 Forwards on Weibo (30 分)——图的bfs
    辅导员
    辅导员面试
    C程序设计
    Excel VBA 基本概念
    Excel函数
    导入excel表的数据到数据库ssh
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5079477.html
Copyright © 2011-2022 走看看