码迷,mamicode.com
首页 > 编程语言 > 详细

spring4.0源码分析━━━(AOP实现)

时间:2014-11-04 13:19:11      阅读:356      评论:0      收藏:0      [点我收藏+]

标签:style   http   io   color   ar   os   使用   java   for   

  • AOP的概念

         AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面)。这就让一些问题很简单化了,例如:开始我们实现了一些逻辑并上线了,现在客户又来了一个新的需求。要在每次交易之前统计下,或者记录下他们的交易简单资料。而你发现你其他模块可能正好有这部分的功能。那AOP就可以用得上了,使用AOP就可以在不修改源代码的情况下新增这些功能。就是在交易前这个切面,新装你的一些功能。这有点像拦截器和Filter。其实都是一个原理。前面说了解析xml和Bean的实例化。

         而AOP的实现的话都是在我前面两篇spring3.0源码分析的基础上实现。其实AOP算是对自己本身IOC的实例,你学好弄懂AOP。基本IOC的也是懂了。但是这里的AOP也用到了一些新的东西,像Aspect,还有JVM的反射和动态代理。还有CGLIB这里也是有用到的。但是默认的实现是用JVM的动态代理。

 

  • AOP的实例

        AOP用起来还是很简单的。就把xml配置好就算完工了。有Advisor和aspect两种方式来完成。如果是用Advisor的话需要实现AfterReturningAdvice,MethodBeforeAdvice,ThrowsAdvice等接口。而如果用aspect的话则不用继承或者实现其他的类,一个普通的类即可。

     

Java代码  
  1. public class LogAop {  
  2.     private final static Log log = LogFactory.getLog(LogAop.class);  
  3.     public void addLog(){  
  4.         log.info("add log ========================");  
  5.     }  
  6. }  

 

Java代码  
  1. public class BeforeAdvisor implements MethodBeforeAdvice {  
  2.     private final static Log log =LogFactory.getLog(BeforeAdvisor.class);  
  3.       
  4.     private int testSEL;  
  5.   
  6.     @Override  
  7.     public void before(Method method, Object[] args, Object target)  
  8.             throws Throwable {  
  9.         log.info("in before advice and method="+method.getName()+ " args "+args.length);  
  10.     }  
  11.  ..........  

 

Java代码  
  1. public class AfterAdvisor implements AfterReturningAdvice {  
  2.     private final static Log log =LogFactory.getLog(AfterAdvisor.class);  
  3.       
  4. ........  
  5.   
  6.     @Override  
  7.     public void afterReturning(Object returnValue, Method method,  
  8.             Object[] args, Object target) throws Throwable {  
  9.         // TODO Auto-generated method stub  
  10.         log.info("test sel the testSEL "+testSEL);  
  11.         log.info("after return advice");  
  12.     }  
  13.   
  14. }  

 

 

     而配置文件如下:

Java代码  
  1. <bean id="LogAop" class="com.zzx.study.aop.LogAop" />  
  2. <bean id="beforeAdvisor" class="com.zzx.study.aop.BeforeAdvisor" >  
  3.    <property name="testSEL" value="11"/>  
  4. </bean>  
  5. <bean id="beforeAdvisor2" class="com.zzx.study.aop.BeforeAdvisor2" >  
  6.    <property name="testSEL" value="23"/>  
  7. </bean>  
  8. <bean id="afterAdvisor" class="com.zzx.study.aop.AfterAdvisor" >  
  9.    <property name="testSEL" value="11"/>  
  10. </bean>  
  11. <aop:config>  
  12.    <aop:pointcut expression="execution(* com.zzx.study.di.BankSecurityDaoImpl.add(..))" id="target" />  
  13.    <aop:pointcut expression="execution(* com.zzx.study.di.Ban*.ad*(..))" id="nonePointCutTest" />  
  14.    <aop:advisor id="bid" pointcut-ref="target" advice-ref="beforeAdvisor" />  
  15.    <aop:advisor id="noAdvisor" pointcut-ref="nonePointCutTest" advice-ref="beforeAdvisor2" />  
  16.    <aop:advisor id="aid" pointcut-ref="target" advice-ref="afterAdvisor" />  
  17.    <aop:aspect ref="LogAop" >  
  18.        <aop:after method="addLog"  pointcut-ref="target"/>  
  19.    </aop:aspect>  
  20. </aop:config>    

       向上面实现后则如果执行BankSecurityDaoImpl的add方法前就会执行BeforeAdvisor的before方法,然后执行add方法,最后是LogAop的addLog方法,AfterAdvisor的afterReturning方法。这里还可以让Advisor实现Order定义这些执行的前后。

Java代码   bubuko.com,布布扣
  1. public class BeforeAdvisor implements MethodBeforeAdvice,Ordered {  
  2.     ............  
  3.   
  4.     @Override  
  5.     public int getOrder() {  
  6.         // TODO Auto-generated method stub  
  7.         return 2;  
  8.     }  
  9.   
  10. }  

 

      这里的有一个getOrder方法,返回int值,越小则越先执行。

 

  • AOP在spring中的实现

       在解析xml的时候说过,如果发现不是bean标签,则会是不同的类来解析。解析aop的为http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler。也就是AopNamespaceHandler类。进去到AopNamespaceHandler类中parse方法,实际是调用其父类的NamespaceHandlerSupport的parse方法。

Java代码  
  1. private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {  
  2.         String localName = parserContext.getDelegate().getLocalName(element);  
  3.         BeanDefinitionParser parser = this.parsers.get(localName);  
  4.         if (parser == null) {  
  5.             parserContext.getReaderContext().fatal(  
  6.                     "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);  
  7.         }  
  8.         return parser;  
  9. }  

 这里的parses是在解析xml的时候初始化。

Java代码  
  1. public void init() {  
  2.         // In 2.0 XSD as well as in 2.1 XSD.  
  3.         registerBeanDefinitionParser("config"new ConfigBeanDefinitionParser());  
  4.         registerBeanDefinitionParser("aspectj-autoproxy"new AspectJAutoProxyBeanDefinitionParser());  
  5.         registerBeanDefinitionDecorator("scoped-proxy"new ScopedProxyBeanDefinitionDecorator());  
  6.   
  7.         // Only in 2.0 XSD: moved to context namespace as of 2.1  
  8.         registerBeanDefinitionParser("spring-configured"new SpringConfiguredBeanDefinitionParser());  
  9. }  

 

 

 如果是config标签,则是用ConfigBeanDefinitionParser类了,如果是aspectj-autoproxy标签则是用AspectJAutoProxyBeanDefinitionParser类来解析了。其实这两个的解析最终都是向DefaultListableBeanFactory中注册class为AspectJAwareAdvisorAutoProxyCreator的BeanDefinition。而AspectJAwareAdvisorAutoProxyCreator是有实现BeanPostProcessor、BeanFactoryAware接口的。而实例化一个bean的时候会经过这些BeanPostProcessor的处理。也就是这些BeanPostProcessor最终实现了把目标对象代理掉,而用代理前后spring就会调用到配置的这些Advisor来处理一些业务逻辑了。其中的BeanFactoryAware接口是把BeanFactory注入到AspectJAwareAdvisorAutoProxyCreator这个类中,而最终执行方法前通过这里注入的BeanFactory得到这些Advisor类并调用。

 

这里讲使用java动态代理的实现。在JdkDynamicAopProxy类中。使用到了责任链的模式,会先得到一个Advisor的list,然后在list中用链的方式执行下去。如果chain不是空的则会到ReflectiveMethodInvocation类中执行processed方法。

Java代码  
  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  2.         MethodInvocation invocation;  
  3.         Object oldProxy = null;  
  4.         boolean setProxyContext = false;  
  5.   
  6.         TargetSource targetSource = this.advised.targetSource;  
  7.         Class targetClass = null;  
  8.         Object target = null;  
  9.   
  10.         try {  
  11.             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {  
  12.                 // The target does not implement the equals(Object) method itself.  
  13.                 return equals(args[0]);  
  14.             }  
  15.             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {  
  16.                 // The target does not implement the hashCode() method itself.  
  17.                 return hashCode();  
  18.             }  
  19.             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&  
  20.                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
  21.                 // Service invocations on ProxyConfig with the proxy config...  
  22.                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);  
  23.             }  
  24.   
  25.             Object retVal;  
  26.   
  27.             if (this.advised.exposeProxy) {  
  28.                 // Make invocation available if necessary.  
  29.                 oldProxy = AopContext.setCurrentProxy(proxy);  
  30.                 setProxyContext = true;  
  31.             }  
  32.   
  33.             // May be null. Get as late as possible to minimize the time we "own" the target,  
  34.             // in case it comes from a pool.  
  35.             target = targetSource.getTarget();  
  36.             if (target != null) {  
  37.                 targetClass = target.getClass();  
  38.             }  
  39.   
  40.             // Get the interception chain for this method.  
  41.             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  42.   
  43.             // Check whether we have any advice. If we don‘t, we can fallback on direct  
  44.             // reflective invocation of the target, and avoid creating a MethodInvocation.  
  45.             if (chain.isEmpty()) {  
  46.                 // We can skip creating a MethodInvocation: just invoke the target directly  
  47.                 // Note that the final invoker must be an InvokerInterceptor so we know it does  
  48.                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.  
  49.                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);  
  50.             }  
  51.             else {  
  52.                 // We need to create a method invocation...  
  53.                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  
  54.                 // Proceed to the joinpoint through the interceptor chain.  
  55.                 retVal = invocation.proceed();  
  56.             }  
  57.   
  58.             // Massage return value if necessary.  
  59.             if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&  
  60.                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
  61.                 // Special case: it returned "this" and the return type of the method  
  62.                 // is type-compatible. Note that we can‘t help if the target sets  
  63.                 // a reference to itself in another returned object.  
  64.                 retVal = proxy;  
  65.             }  
  66.             return retVal;  
  67.         }  
  68.         finally {  
  69.             if (target != null && !targetSource.isStatic()) {  
  70.                 // Must have come from TargetSource.  
  71.                 targetSource.releaseTarget(target);  
  72.             }  
  73.             if (setProxyContext) {  
  74.                 // Restore old proxy.  
  75.                 AopContext.setCurrentProxy(oldProxy);  
  76.             }  
  77.         }  
  78. }  

 

 

Java代码  
  1. public Object proceed() throws Throwable {  
  2.         //  We start with an index of -1 and increment early.  
  3.         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
  4.             return invokeJoinpoint();  
  5.         }  
  6.   
  7.         Object interceptorOrInterceptionAdvice =  
  8.             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  9.         if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
  10.             // Evaluate dynamic method matcher here: static part will already have  
  11.             // been evaluated and found to match.  
  12.             InterceptorAndDynamicMethodMatcher dm =  
  13.                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
  14.             if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
  15.                 return dm.interceptor.invoke(this);  
  16.             }  
  17.             else {  
  18.                 // Dynamic matching failed.  
  19.                 // Skip this interceptor and invoke the next in the chain.  
  20.                 return proceed();  
  21.             }  
  22.         }  
  23.         else {  
  24.             // It‘s an interceptor, so we just invoke it: The pointcut will have  
  25.             // been evaluated statically before this object was constructed.  
  26.             return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  27.         }  
  28. }  

 

这里的interceptorOrInterceptionAdvice都是MethodInterceptor类型。因为解析xml的时候,会把<aop:advisor>最终生成class为DefaultBeanFactoryPointcutAdvisor类的BeanDefinition类,而<aop:aspect>会生成class为AspectJPointcutAdvisor的BeanDefinition。又通过DefaultAdvisorAdapterRegistry类把Advisor转换为MethodInterceptor类。

Java代码  
  1. public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {  
  2.   
  3. ...........................  
  4.   
  5.   
  6.     public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {  
  7.         List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);  
  8.         Advice advice = advisor.getAdvice();  
  9.         if (advice instanceof MethodInterceptor) {  
  10.             interceptors.add((MethodInterceptor) advice);  
  11.         }  
  12.         for (AdvisorAdapter adapter : this.adapters) {  
  13.             if (adapter.supportsAdvice(advice)) {  
  14.                 interceptors.add(adapter.getInterceptor(advisor));  
  15.             }  
  16.         }  
  17.         if (interceptors.isEmpty()) {  
  18.             throw new UnknownAdviceTypeException(advisor.getAdvice());  
  19.         }  
  20.         return interceptors.toArray(new MethodInterceptor[interceptors.size()]);  
  21.     }  
  22.   
  23.     public void registerAdvisorAdapter(AdvisorAdapter adapter) {  
  24.         this.adapters.add(adapter);  
  25.     }  
  26.   
  27. }  

    像beforeAdvisor则转换为MethodBeforeAdviceInterceptor这样的拦截器了。在这个拦截器中的invoke方法中会发现会先调用自己advice的before方法,也就是你自己实现的业务类。接着又会调用processed,也就是连接链的方式,一直调用下去,知道chain中所有都执行完成。

Java代码  
  1. public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {  
  2.   
  3.     private MethodBeforeAdvice advice;  
  4.   
  5.   
  6.     /** 
  7.      * Create a new MethodBeforeAdviceInterceptor for the given advice. 
  8.      * @param advice the MethodBeforeAdvice to wrap 
  9.      */  
  10.     public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {  
  11.         Assert.notNull(advice, "Advice must not be null");  
  12.         this.advice = advice;  
  13.     }  
  14.   
  15.     public Object invoke(MethodInvocation mi) throws Throwable {  
  16.         this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );  
  17.         return mi.proceed();  
  18.     }  
  19.   
  20. }  

     

       这里的advice

spring4.0源码分析━━━(AOP实现)

标签:style   http   io   color   ar   os   使用   java   for   

原文地址:http://my.oschina.net/u/555639/blog/340499

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!