• 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

  • 相关阅读:
    网站优化网站前端优firedebug详情(转)
    网站优化HTTP REQUEST与web service 性能测试比较
    网站优化谈百度、Google搜索引擎最近的变化(转网文)
    网站优化QQ用户粘性
    网站优化广州SEM大会小节
    网站优化前端设计在不同浏览器上面的兼容
    网站优化网站前端优化好帮手
    谈谈我对CSS层叠的理解
    获取浏览器的可视区域尺寸
    【转载】关于setTimeout,理解JavaScript定时机制
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5079477.html
Copyright © 2020-2023  润新知