Spring AOP实现原理

简介:

对Spring平台或者说生态系统来说,AOP是Spring框架的核心功能模块之一。AOP与IOC容器的结合使用, 为应用开发或者Spring自身功能的扩展都提供了许多便利。Spring AOP的实现和其他特性的实现一样,非常丰富,除了可以使用Spring本身提供的AOP实现之外,还封装了业界优秀的AOP解决方案AspectJ来让应用使用。在这里,主要对Spring自身的AOP实现原理做一些解析;在这个AOP实现中,Spring充分利用了IOC容器Proxy代理对象以及AOP拦截器的功能特性,通过这些对AOP基本功能的封装机制,为用户提供了AOP的实现框架。所以,要了解这些AOP的基本实现,需要我们对Java 的Proxy机制有一些基本了解。 

AOP实现的基本线索 

AOP实现中,可以看到三个主要的步骤,一个是代理对象的生成,然后是拦截器的作用,然后是Aspect编织的实现。AOP框架的丰富,很大程度体现在这三个具体实现中,所具有的丰富的技术选择,以及如何实现与IOC容器的无缝结合。毕竟这也是一个非常核心的模块,需要满足不同的应用需求带来的解决方案需求。 
在Spring AOP的实现原理中,我们主要举ProxyFactoryBean(aspectj方案则是AspectJProxyFactory)的实现作为例子和实现的基本线索进行分析;很大一个原因,是因为ProxyFactoryBean是在Spring IoC环境中,创建AOP应用的最底层方法,从中,可以看到一条实现AOP的基本线索。在ProxyFactoryBean中,它的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象,是从getObject()方法作为入口完成的。然后为proxy代理对象配置advisor链,这个配置是在initializeAdvisorChain方法中完成的,这样就为生成AOP代理对象做好了准备。代码如下;

ProxyFactoryBean

 

Java代码   收藏代码
  1. public Object getObject() throws BeansException {  
  2.         initializeAdvisorChain();  
  3.         if (isSingleton()) {  
  4.             return getSingletonInstance();  
  5.         }  
  6.         else {  
  7.             if (this.targetName == null) {  
  8.                 logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +  
  9.                         "Enable prototype proxies by setting the 'targetName' property.");  
  10.             }  
  11.             return newPrototypeInstance();  
  12.         }  
  13.     }  

 ProxyCreatorSupport

 

 

Java代码   收藏代码
  1. protected final synchronized AopProxy createAopProxy() {  
  2.         if (!this.active) {  
  3.             activate();  
  4.         }  
  5.         return getAopProxyFactory().createAopProxy(this);  
  6.     }  

 DefaultAopProxyFactory

 

 

Java代码   收藏代码
  1. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {  
  2.         if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {  
  3.             Class targetClass = config.getTargetClass();  
  4.             if (targetClass == null) {  
  5.                 throw new AopConfigException("TargetSource cannot determine target class: " +  
  6.                         "Either an interface or a target is required for proxy creation.");  
  7.             }  
  8.             if (targetClass.isInterface()) {  
  9.                 return new JdkDynamicAopProxy(config);  
  10.             }  
  11.             return CglibProxyFactory.createCglibProxy(config);  
  12.         }  
  13.         else {  
  14.             return new JdkDynamicAopProxy(config);  
  15.         }  
  16.     }  

我们回忆一下我们做过的jdk代理的例子:

 

 

Java代码   收藏代码
  1. UserMgr mgr = new UserMgrImpl();  
  2. InvocationHandler h = new TransactionHandler(mgr);  
  3. UserMgr u = (UserMgr) Proxy.newProxyInstance(UserMgr.class, h);  

 生成的代理是比如$Proxy34,h是$Proxy34的成员变量,

Java代码   收藏代码
  1. public class Proxy implements java.io.Serializable {  
  2.   /** prefix for all proxy class names */  
  3.     private final static String proxyClassNamePrefix = "$Proxy";  
  4.   /** 
  5.      * the invocation handler for this proxy instance. 
  6.      * @serial 
  7.      */  
  8.     protected InvocationHandler h;  
  9. }  

 

在spring aop中正是JdkDynamicAopProxy。那么重点来了,我们就从JdkDynamicAopProxy的invoke方法看起:

 

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.         Class<?> returnType = method.getReturnType();  
  60.         if (retVal != null && retVal == target && returnType.isInstance(proxy) &&  
  61.                 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
  62.             // Special case: it returned "this" and the return type of the method  
  63.             // is type-compatible. Note that we can't help if the target sets  
  64.             // a reference to itself in another returned object.  
  65.             retVal = proxy;  
  66.         }  
  67.         else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {  
  68.             throw new AopInvocationException(  
  69.                     "Null return value from advice does not match primitive return type for: " + method);  
  70.         }  
  71.         return retVal;  
  72.     }  
  73.     finally {  
  74.         if (target != null && !targetSource.isStatic()) {  
  75.             // Must have come from TargetSource.  
  76.             targetSource.releaseTarget(target);  
  77.         }  
  78.         if (setProxyContext) {  
  79.             // Restore old proxy.  
  80.             AopContext.setCurrentProxy(oldProxy);  
  81.         }  
  82.     }  
  83. }  

 ReflectiveMethodInvocation implements ProxyMethodInvocation extends MethodInvocation extends Invocation extends Joinpoint

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 { // eg. <span style="line-height: 25.2px; white-space: normal;">ExposeInvocationInterceptor</span>  
  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. }  

 

Java代码   收藏代码
  1. package org.aopalliance.intercept; // Aop联盟  
  2.   
  3. import java.lang.reflect.AccessibleObject;  
  4.   
  5. public interface Joinpoint {  
  6.     Object proceed() throws Throwable;  
  7.   
  8.     Object getThis();  
  9.   
  10.     AccessibleObject getStaticPart();  
  11. }  

 interceptor.invoker - eg. MethodBeforeAdviceInterceptor

Java代码   收藏代码
  1. public Object invoke(MethodInvocation mi) throws Throwable {  
  2.     this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );  
  3.     return mi.proceed(); // 又回归到了上面的调用  
  4. }  

 值得注意的是,虽然切面可以只用到一个类的部分方法上,但我们调用其他方法时,仍然会经历上面的逻辑,此时拦截器链里只有一个interceptor - ExposeInvocationInterceptor

Java代码   收藏代码
  1. public Object invoke(MethodInvocation mi) throws Throwable {  
  2.     MethodInvocation oldInvocation = invocation.get();  
  3.     invocation.set(mi);  
  4.     try {  
  5.         return mi.proceed();  
  6.     }  
  7.     finally {  
  8.         invocation.set(oldInvocation);  
  9.     }  
  10. }  

 

 Aop应用参考:

一、分库分表http://wely.iteye.com/blog/2275725

二、方法性能监控

Java代码   收藏代码
  1. package com.itlong.bjxizhan.support.web.service.monitor;  
  2.   
  3. import org.aspectj.lang.ProceedingJoinPoint;  
  4. import org.aspectj.lang.annotation.Around;  
  5. import org.aspectj.lang.annotation.Aspect;  
  6.   
  7. /** 
  8.  * Created by shenhongxi on 2016/8/10. 
  9.  */  
  10. @Aspect  
  11. public class MonitorAspect {  
  12.   
  13.     private String tagPrefix;  
  14.   
  15.     @Around(  
  16.             value = "execution(* *(..)) && @annotation(monitor)",  
  17.             argNames = "pjp,monitor"  
  18.     )  
  19.     public Object doUmpLogging(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {  
  20.         // String tag = monitor.tag();  
  21.         // boolean heart = monitor.heart();  
  22.         long start = System.currentTimeMillis();  
  23.         // record invocation (times)  
  24.         Object obj = null;  
  25.         try {  
  26.             obj = pjp.proceed();  
  27.         } catch (Exception e) {  
  28.             // record error  
  29.             throw e;  
  30.         } finally {  
  31.             long end = System.currentTimeMillis();  
  32.             // record time -> end - start  
  33.         }  
  34.         return obj;  
  35.     }  
  36.   
  37.     public String getTagPrefix() {  
  38.         return tagPrefix;  
  39.     }  
  40.   
  41.     public void setTagPrefix(String tagPrefix) {  
  42.         this.tagPrefix = tagPrefix;  
  43.     }  
  44. }  
  45.   
  46. @Retention(RetentionPolicy.RUNTIME)  
  47. @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})  
  48. public @interface Monitor {  
  49.     String DEFAULT_TAG_NAME = "@@USE_METHOD_NAME";  
  50.   
  51.     String tag() default "@@USE_METHOD_NAME";  
  52.   
  53.     String message() default "";  
  54.   
  55.     boolean heart() default false;  
  56.   
  57. }  

 另外,性能监控拦截器可参考org.springframework.aop.interceptor.PerformanceMonitorInterceptor


原文链接:[http://wely.iteye.com/blog/2313924]

相关文章
|
17天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
27 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
2天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
|
23天前
|
Java Spring 容器
Spring底层原理大致脉络
Spring底层原理大致脉络
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
27天前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
44 2
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
117 9
|
30天前
|
设计模式 Java Spring
Spring Boot监听器的底层实现原理
Spring Boot监听器的底层实现原理主要基于观察者模式(也称为发布-订阅模式),这是设计模式中用于实现对象之间一对多依赖的一种常见方式。在Spring Boot中,监听器的实现依赖于Spring框架提供的事件监听机制。
25 1
|
2月前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
99 3
|
26天前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
42 0
|
27天前
|
XML 前端开发 Java
拼多多1面:聊聊Spring MVC的工作原理!
本文详细剖析了Spring MVC的工作原理,涵盖其架构、工作流程及核心组件。Spring MVC采用MVC设计模式,通过DispatcherServlet、HandlerMapping、Controller和ViewResolver等组件高效处理Web请求。文章还探讨了DispatcherServlet的初始化和请求处理流程,以及HandlerMapping和Controller的角色。通过理解这些核心概念,开发者能更好地构建可维护、可扩展的Web应用。适合面试准备和技术深挖
40 0