Spring IOC及AOP学习总结
2014-05-08 15:34
609 查看
一、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
相关文章推荐
- Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC
- Spring IOC及AOP学习总结
- Spring学习总结——静态代理、JDK与CGLIB动态代理、AOP+IoC
- Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC
- Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC
- Spring学习之AOP总结帖
- Spring学习总结(一)——Spring实现IoC的多种方式
- Spring学习总结(1)——Spring AOP的概念理解
- Spring学习总结——Spring实现AOP的多种方式
- SpringAOP之学习总结
- Spring学习总结——Spring实现AOP的多种方式
- spring 学习 AOP和IOC
- Spring学习总结——Spring实现AOP的多种方式
- 用代码学习Spring:IoC、AOP
- Spring学习总结之面向切面(AOP)
- Spring学习总结(三)——Spring实现AOP的多种方式
- Spring学习总结(一)——Spring实现IoC的多种方式
- Spring学习总结5(IOC-基于注解Annotation)
- spring学习总结(七):IOC & DI 配置Bean之bean的生命周期及bean的配置方式
- spring学习总结二-----面向切面编程(AOP)思想