精华内容
下载资源
问答
  • spring aop实现原理

    2019-03-15 01:02:33
    NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927
  • 什么是AOP  AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共...
  • spring Aop 实现原理

    2019-08-18 12:48:53
    Aop(面向切面思想,不是指Spring Aop):面向切面编程,Aop的实现分为两种,动态切面(运行期织入增强代码)和静态切面...在spring实现原理中主要关注两个方面: 1.动态代理对象是如何创建的 2.动态代理的拦...

    Aop(面向切面思想,不是指Spring Aop):面向切面编程,Aop的实现分为两种,动态切面(运行期织入增强代码)和静态切面(编译器在编译期织入)。静态切面是AspectJ,Spring Aop采用动态切面,即jdk动态代理和CGLIB动态代理来实现。Spring默认是使用jdk动态代理实现Aop。

    在spring的实现原理中主要关注两个方面:

    • 1.动态代理对象AopProxy是如何创建的
    • 2.动态代理的拦截器对象是如何完成横切面的织入的

    Spring Aop 代理对象的生成

    Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。下面就来分析一下如何使用JDK来生成动态代理对象。具体的生成代码放在JdkDynamicAopProxy这个类中

    /**
        * <ol>
        * <li>获取代理类要实现的接口,除了Advised对象中配置的,还会加上SpringProxy, Advised(opaque=false)
        * <li>检查上面得到的接口中有没有定义 equals或者hashcode的接口
        * <li>调用Proxy.newProxyInstance创建代理对象
        * </ol>
        */
       public Object getProxy(ClassLoader classLoader) {
           if (logger.isDebugEnabled()) {
               logger.debug("Creating JDK dynamic proxy: target source is " +this.advised.getTargetSource());
           }
           Class[] proxiedInterfaces =AopProxyUtils.completeProxiedInterfaces(this.advised);
           findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
           return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    

    该类本身实现了InvocationHandler接口和invoke方法,这个invoke方法是Proxy代理对象的回调方法,也就是说在代理对象本身在Proxy代理的接口方法被调用时,会去调用invoke方法。下面我们就来分析JdkDynamicAopProxy的invoke方法,这个回调方法完成了Aop编织实现的封装

    在这里插入代码片
    

    拦截器链调用

    展开全文
  • SpringAop实现原理

    千次阅读 2017-12-06 00:00:00
    SpringAop实现原理什么是AOPAOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,...

    SpringAop实现原理

    什么是AOP

    AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

     

    而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

     

    使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

     

    实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。


    AOP使用场景

    AOP用来封装横切关注点,具体可以在下面的场景中使用:

     

    Authentication 权限

    Caching 缓存

    Context passing 内容传递

    Error handling 错误处理

    Lazy loading 懒加载

    Debugging  调试

    logging, tracing, profiling and monitoring 记录跟踪 优化 校准

    Performance optimization 性能优化

    Persistence  持久化

    Resource pooling 资源池

    Synchronization 同步

    Transactions 事务


    AOP相关概念

    方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的 Advisor或拦截器实现。

     

    连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

     

    通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice

     

    切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上

     

    引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口

     

    目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO

     

    AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

     

    织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。


    Spring AOP组件

    下面这种类图列出了Spring中主要的AOP组件



    如何使用Spring AOP

    可以通过配置文件或者编程的方式来使用Spring AOP。

     

    配置可以通过xml文件来进行,大概有四种方式:

    1. 配置ProxyFactoryBean,显式地设置advisors, advice, target等

    2. 配置AutoProxyCreator,这种方式下,还是如以前一样使用定义的bean,但是从容器中获得的其实已经是代理对象

    3. 通过<aop:config>来配置

    4. 通过<aop: aspectj-autoproxy>来配置,使用AspectJ的注解来标识通知及切入点

     

    也可以直接使用ProxyFactory来以编程的方式使用Spring AOP,通过ProxyFactory提供的方法可以设置target对象, advisor等相关配置,最终通过 getProxy()方法来获取代理对象

     

    具体使用的示例可以google. 这里略去


    Spring AOP代理对象的生成

    Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。下面我们来研究一下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中,直接上相关代码:

     

    那这个其实很明了,注释上我也已经写清楚了,不再赘述。

     

    下面的问题是,代理对象生成了,那切面是如何织入的?

    我们知道InvocationHandler是JDK动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。而通过JdkDynamicAopProxy的签名我们可以看到这个类其实也实现了InvocationHandler,下面我们就通过分析这个类中实现的invoke()方法来具体看下Spring AOP是如何织入切面的。

    主流程可以简述为:

    获取可以应用到此方法上的通知链(Interceptor Chain),如果有,则应用通知,并执行joinpoint; 如果没有,则直接反射执行joinpoint。而这里的关键是通知链是如何获取的以及它又是如何执行的,下面逐一分析下。

     

    首先,从上面的代码可以看到,通知链是通过Advised.getInterceptorsAndDynamicInterceptionAdvice()这个方法来获取的,我们来看下这个方法的实现:


    可以看到实际的获取工作其实是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()这个方法来完成的,获取到的结果会被缓存。

    下面来分析下这个方法的实现:

     

    这个方法执行完成后,Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor.

     

    接下来我们再看下得到的拦截器链是怎么起作用的。

            

             从这段代码可以看出,如果得到的拦截器链为空,则直接反射调用目标方法,否则创建MethodInvocation,调用其proceed方法,触发拦截器链的执行,来看下具体代码


    代码也比较简单,这里不再赘述。

    展开全文
  • Spring AOP实现原理

    万次阅读 2018-05-18 14:55:12
    1、Spring AOPspring的面向切面编程,是面向对象编程的一种补充,用于处理系统中分布的各个模块的横切关注点,...Spring AOP的动态代理主要有两种方式实现,JDK动态代理和cglib动态代理。JDK动态代理通过反射来接...

    1、Spring AOP

    Spring AOP的面向切面编程,是面向对象编程的一种补充,用于处理系统中分布的各个模块的横切关注点,比如说事务管理、日志、缓存等。它是使用动态代理实现的,在内存中临时为方法生成一个AOP对象,这个对象包含目标对象的所有方法,在特定的切点做了增强处理,并回调原来的方法。

    Spring AOP的动态代理主要有两种方式实现,JDK动态代理和cglib动态代理。JDK动态代理通过反射来接收被代理的类,但是被代理的类必须实现接口,核心是InvocationHandler和Proxy类。cglib动态代理的类一般是没有实现接口的类,cglib是一个代码生成的类库,可以在运行时动态生成某个类的子类,所以,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

    Spring AOP使用哪种方式实现代理的逻辑在org.springframework.aop.framework.DefaultAopProxyFactory中实现的。

    package org.springframework.aop.framework;
    
    import java.io.Serializable;
    import java.lang.reflect.Proxy;
    
    import org.springframework.aop.SpringProxy;
    
    @SuppressWarnings("serial")
    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    
    	@Override
    	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.");
    			}
                            //判断如果是接口,或者是被代理的类,则使用JDK动态代理
                            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
                            //否则用cglib动态代理,(没有实现接口的类)
                            return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			//默认使用jdk动态代理
                            return new JdkDynamicAopProxy(config);
    		}
    	}
    
    	/**
    	* 确定提供的{@link AdvisedSupport}是否仅有
            * 指定了{@link org.springframework.aop.SpringProxy}接口
            *(或者根本没有指定的代理接口)。
            */
    	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
    		Class<?>[] ifcs = config.getProxiedInterfaces();
    		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    	}
    
    }
    

    2、Spring AOP类结构图

    最核心的处理是InvocationHandler接口中的invoke()方法


    3、JdkDynamicAopProxy动态代理

    JdkDynamicAopProxy源码:

    package org.springframework.aop.framework;
    
    import java.io.Serializable;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.List;
    
    import org.aopalliance.intercept.MethodInvocation;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.aop.AopInvocationException;
    import org.springframework.aop.RawTargetAccess;
    import org.springframework.aop.TargetSource;
    import org.springframework.aop.support.AopUtils;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    
    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    
    	private static final long serialVersionUID = 5531744639992436476L;
    
    	/*
             *注意:我们可以避免这个类和CGLIB之间的代码重复
            *代理通过重构“调用”到模板方法中。 但是,这种方法
            *与复制粘贴解决方案相比,至少增加了10%的性能开销,所以我们牺牲了
            *优雅的表现。 (我们有一个很好的测试套件来确保不同的
            *代理行为相同:-)
            *这样,我们也可以更轻松地利用每个班级中的次要优化。
            */
    
            / **我们使用静态日志来避免序列化问题* /
    	private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
    
    	/** Config used to configure this proxy */
    	private final AdvisedSupport advised;
    
    
          //代理接口上是否定义了{@link #hashCode}方法?
          private boolean equalsDefined;
    
    //代理接口上是否定义了{@link #hashCode}方法?private boolean hashCodeDefined;/** *为给定的AOP配置构造一个新的JdkDynamicAopProxy。
            * @param将AOP配置配置为AdvisedSupport对象
            *如果配置无效,则引发AopConfigException。 我们试图提供信息
            *在这种情况下是例外情况,而不是在稍后发生神秘故障。 */public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {Assert.notNull(config, "AdvisedSupport must not be null");if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {throw new AopConfigException("No advisors and no TargetSource specified");}this.advised = config;}@Overridepublic Object getProxy() {return getProxy(ClassUtils.getDefaultClassLoader());}@Overridepublic Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {for (Class<?> proxiedInterface : proxiedInterfaces) {Method[] methods = proxiedInterface.getDeclaredMethods();for (Method method : methods) {if (AopUtils.isEqualsMethod(method)) {this.equalsDefined = true;}if (AopUtils.isHashCodeMethod(method)) {this.hashCodeDefined = true;}if (this.equalsDefined && this.hashCodeDefined) {return;}}}}/** * Implementation of {@code InvocationHandler.invoke}. * <p>Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */@Overridepublic 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 {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}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.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.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}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.Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target && returnType.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;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}@Overridepublic boolean equals(Object other) {if (other == this) {return true;}if (other == null) {return false;}JdkDynamicAopProxy otherProxy;if (other instanceof JdkDynamicAopProxy) {otherProxy = (JdkDynamicAopProxy) other;}else if (Proxy.isProxyClass(other.getClass())) {InvocationHandler ih = Proxy.getInvocationHandler(other);if (!(ih instanceof JdkDynamicAopProxy)) {return false;}otherProxy = (JdkDynamicAopProxy) ih;}else {// Not a valid comparison...return false;}// 如果我们到达这里,otherProxy是另一个AopProxy。return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);}/** * 代理使用TargetSource的哈希码。. */@Overridepublic int hashCode() {return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();}}从源码可以看到,JdkDynamicAopProxy同时实现了AopProxy, InvocationHandler, Serializable三个接口,其中InvocationHandler是动态代理的核心接口。所有的动态代理都是通过InvocationHandler.invoke()方法实现的。


    4、cgLibAopProxy动态代理

    CglibAopProxy使用getProxy()方法来实现代理,getProxy中使生成的代理对象的方法都委托到了getCallbacks()方法,然后是调用createProxyClassAndInstance()方法来执行代理。createProxyClassAndInstance()又在ObjenesisCglibAopProxy类中重写。具体看下源码:

    CglibAopProxy源码,只保留了几个核心的方法:

    package org.springframework.aop.framework;
    
    @SuppressWarnings("serial")
    class CglibAopProxy implements AopProxy, Serializable {
    
    	// Constants for CGLIB callback array indices
    	private static final int AOP_PROXY = 0;
    	private static final int INVOKE_TARGET = 1;
    	private static final int NO_OVERRIDE = 2;
    	private static final int DISPATCH_TARGET = 3;
    	private static final int DISPATCH_ADVISED = 4;
    	private static final int INVOKE_EQUALS = 5;
    	private static final int INVOKE_HASHCODE = 6;
    
    
    	/** Logger available to subclasses; static to optimize serialization */
    	protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
    
    	/** Keeps track of the Classes that we have validated for final methods */
    	private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<Class<?>, Boolean>();
    
    
    	/** The configuration used to configure this proxy */
    	protected final AdvisedSupport advised;
    
    	protected Object[] constructorArgs;
    
    	protected Class<?>[] constructorArgTypes;
    
    	/** Dispatcher used for methods on Advised */
    	private final transient AdvisedDispatcher advisedDispatcher;
    
    	private transient Map<String, Integer> fixedInterceptorMap;
    
    	private transient int fixedInterceptorOffset;
    
    
    	/**
    	 * Create a new CglibAopProxy for the given AOP configuration.
    	 * @param config the AOP configuration as AdvisedSupport object
    	 * @throws AopConfigException if the config is invalid. We try to throw an informative
    	 * exception in this case, rather than let a mysterious failure happen later.
    	 */
    	public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
    		Assert.notNull(config, "AdvisedSupport must not be null");
    		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
    			throw new AopConfigException("No advisors and no TargetSource specified");
    		}
    		this.advised = config;
    		this.advisedDispatcher = new AdvisedDispatcher(this.advised);
    	}
    
    	/**
    	 * Set constructor arguments to use for creating the proxy.
    	 * @param constructorArgs the constructor argument values
    	 * @param constructorArgTypes the constructor argument types
    	 */
    	public void setConstructorArguments(Object[] constructorArgs, Class<?>[] constructorArgTypes) {
    		if (constructorArgs == null || constructorArgTypes == null) {
    			throw new IllegalArgumentException("Both 'constructorArgs' and 'constructorArgTypes' need to be specified");
    		}
    		if (constructorArgs.length != constructorArgTypes.length) {
    			throw new IllegalArgumentException("Number of 'constructorArgs' (" + constructorArgs.length +
    					") must match number of 'constructorArgTypes' (" + constructorArgTypes.length + ")");
    		}
    		this.constructorArgs = constructorArgs;
    		this.constructorArgTypes = constructorArgTypes;
    	}
    
    
    	@Override
    	public Object getProxy() {
    		return getProxy(null);
    	}
    
    	@Override
    	public Object getProxy(ClassLoader classLoader) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
    		}
    
    		try {
    			Class<?> rootClass = this.advised.getTargetClass();
    			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
    
    			Class<?> proxySuperClass = rootClass;
    			if (ClassUtils.isCglibProxyClass(rootClass)) {
    				proxySuperClass = rootClass.getSuperclass();
    				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
    				for (Class<?> additionalInterface : additionalInterfaces) {
    					this.advised.addInterface(additionalInterface);
    				}
    			}
    
    			// Validate the class, writing log messages as necessary.
    			validateClassIfNecessary(proxySuperClass, classLoader);
    
    			// Configure CGLIB Enhancer...
    			Enhancer enhancer = createEnhancer();
    			if (classLoader != null) {
    				enhancer.setClassLoader(classLoader);
    				if (classLoader instanceof SmartClassLoader &&
    						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
    					enhancer.setUseCache(false);
    				}
    			}
    			enhancer.setSuperclass(proxySuperClass);
    			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    			enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
    
    			Callback[] callbacks = getCallbacks(rootClass);
    			Class<?>[] types = new Class<?>[callbacks.length];
    			for (int x = 0; x < types.length; x++) {
    				types[x] = callbacks[x].getClass();
    			}
    			// fixedInterceptorMap only populated at this point, after getCallbacks call above
    			enhancer.setCallbackFilter(new ProxyCallbackFilter(
    					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    			enhancer.setCallbackTypes(types);
    
    			// Generate the proxy class and create a proxy instance.
    			return createProxyClassAndInstance(enhancer, callbacks);
    		}
    		catch (CodeGenerationException ex) {
    			throw new AopConfigException("Could not generate CGLIB subclass of class [" +
    					this.advised.getTargetClass() + "]: " +
    					"Common causes of this problem include using a final class or a non-visible class",
    					ex);
    		}
    		catch (IllegalArgumentException ex) {
    			throw new AopConfigException("Could not generate CGLIB subclass of class [" +
    					this.advised.getTargetClass() + "]: " +
    					"Common causes of this problem include using a final class or a non-visible class",
    					ex);
    		}
    		catch (Exception ex) {
    			// TargetSource.getTarget() failed
    			throw new AopConfigException("Unexpected AOP exception", ex);
    		}
    	}
    
    	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    		enhancer.setInterceptDuringConstruction(false);
    		enhancer.setCallbacks(callbacks);
    		return (this.constructorArgs != null ?
    				enhancer.create(this.constructorArgTypes, this.constructorArgs) :
    				enhancer.create());
    	}
    
    
        	private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    		// Parameters used for optimisation choices...
    		boolean exposeProxy = this.advised.isExposeProxy();
    		boolean isFrozen = this.advised.isFrozen();
    		boolean isStatic = this.advised.getTargetSource().isStatic();
    
    		// Choose an "aop" interceptor (used for AOP calls).
    		Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    
    		// Choose a "straight to target" interceptor. (used for calls that are
    		// unadvised but can return this). May be required to expose the proxy.
    		Callback targetInterceptor;
    		if (exposeProxy) {
    			targetInterceptor = isStatic ?
    					new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
    					new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    		}
    		else {
    			targetInterceptor = isStatic ?
    					new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
    					new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    		}
    
    		// Choose a "direct to target" dispatcher (used for
    		// unadvised calls to static targets that cannot return this).
    		Callback targetDispatcher = isStatic ?
    				new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
    
    		Callback[] mainCallbacks = new Callback[] {
    				aopInterceptor,  // for normal advice
    				targetInterceptor,  // invoke target without considering advice, if optimized
    				new SerializableNoOp(),  // no override for methods mapped to this
    				targetDispatcher, this.advisedDispatcher,
    				new EqualsInterceptor(this.advised),
    				new HashCodeInterceptor(this.advised)
    		};
    
    		Callback[] callbacks;
    
    		// If the target is a static one and the advice chain is frozen,
    		// then we can make some optimisations by sending the AOP calls
    		// direct to the target using the fixed chain for that method.
    		if (isStatic && isFrozen) {
    			Method[] methods = rootClass.getMethods();
    			Callback[] fixedCallbacks = new Callback[methods.length];
    			this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
    
    			// TODO: small memory optimisation here (can skip creation for methods with no advice)
    			for (int x = 0; x < methods.length; x++) {
    				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
    				fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
    						chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
    				this.fixedInterceptorMap.put(methods[x].toString(), x);
    			}
    
    			// Now copy both the callbacks from mainCallbacks
    			// and fixedCallbacks into the callbacks array.
    			callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
    			System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
    			System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
    			this.fixedInterceptorOffset = mainCallbacks.length;
    		}
    		else {
    			callbacks = mainCallbacks;
    		}
    		return callbacks;
    	}
    }
    

    ObjenesisCglibAopProxy的源码,其中重写了createProxyClassAndInstance()方法,该方法中使用了SpringObjenesis来生成代理实例对象。

    package org.springframework.aop.framework;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.cglib.proxy.Callback;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.Factory;
    import org.springframework.objenesis.SpringObjenesis;
    
    @SuppressWarnings("serial")
    class ObjenesisCglibAopProxy extends CglibAopProxy {
    
    	private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class);
    
    	private static final SpringObjenesis objenesis = new SpringObjenesis();
    
    
    	/**
    	 * Create a new ObjenesisCglibAopProxy for the given AOP configuration.
    	 * @param config the AOP configuration as AdvisedSupport object
    	 */
    	public ObjenesisCglibAopProxy(AdvisedSupport config) {
    		super(config);
    	}
    
    
    	@Override
    	@SuppressWarnings("unchecked")
    	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    		Class<?> proxyClass = enhancer.createClass();
    		Object proxyInstance = null;
    
    		if (objenesis.isWorthTrying()) {
    			try {
    				proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
    			}
    			catch (Throwable ex) {
    				logger.debug("Unable to instantiate proxy using Objenesis, " +
    						"falling back to regular proxy construction", ex);
    			}
    		}
    
    		if (proxyInstance == null) {
    			// Regular instantiation via default constructor...
    			try {
    				proxyInstance = (this.constructorArgs != null ?
    						proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
    						proxyClass.newInstance());
    			}
    			catch (Throwable ex) {
    				throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
    						"and regular proxy instantiation via default constructor fails as well", ex);
    			}
    		}
    
    		((Factory) proxyInstance).setCallbacks(callbacks);
    		return proxyInstance;
    	}
    
    }
    




    展开全文
  • Spring AOP实现原理解析

    2020-08-28 13:28:08
    主要为大家详细介绍了Spring AOP实现原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Spring AOP实现原理简介

    万次阅读 多人点赞 2018-04-28 16:00:53
    AOP联盟标准AOP联盟将AOP体系分为三层,从三层结构可以看出,AOP实现方式有很多种,包括反射、元数据处理、程序处理、拦截器处理等,通过本节学习,你就会看到Spring AOP的实现使用的是Java语言本身的特性,即Java ...

    AOP联盟标准

    AOP联盟将AOP体系分为三层,从三层结构可以看出,AOP实现方式有很多种,包括反射、元数据处理、程序处理、拦截器处理等,通过本节学习,你就会看到Spring AOP的实现使用的是Java语言本身的特性,即Java Proxy代理类、拦截器技术实现。

    AOP简介

    概念

    切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
    连接点(Joinpoint) :程序执行过程中的某一行为。
    通知(Advice) :“切面”对于某个“连接点”所产生的动作。
    切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。
    目标对象(Target Object) :被一个或者多个切面所通知的对象。
    AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。

    通知(Advice)类型
    前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。
    后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。
    返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在<aop:aspect>里面使用<after-returning>元素进行声明。
    环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。
    抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。

    切入点表达式 :如execution(* com.spring.service.*.*(..))

    特点

    1、降低模块之间的耦合度

    2、使系统容易扩展

    3、更好的代码复用。

    时序图


    流程说明

    1)AOP标签的定义解析刘彻骨肯定是从NamespaceHandlerSupport的实现类开始解析的,这个实现类就是AopNamespaceHandler。至于为什么会是从NamespaceHandlerSupport的实现类开始解析的,这个的话我想读者可以去在回去看看Spring自定义标签的解析流程,里面说的比较详细。

    2)要启用AOP,我们一般会在Spring里面配置<aop:aspectj-autoproxy/>  ,所以在配置文件中在遇到aspectj-autoproxy标签的时候我们会采用AspectJAutoProxyBeanDefinitionParser解析器

    3)进入AspectJAutoProxyBeanDefinitionParser解析器后,调用AspectJAutoProxyBeanDefinitionParser已覆盖BeanDefinitionParser的parser方法,然后parser方法把请求转交给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理

    4)进入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法后,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,里面在转发调用给registerOrEscalateApcAsRequired,注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。

    5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法处理完成之后,接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性。如果将proxy-target-class设置为true的话,那么会强制使用CGLIB代理,否则使用jdk动态代理,expose-proxy属性是为了解决有时候目标对象内部的自我调用无法实现切面增强。

    6)最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。

    创建AOP代理

    上面说到AOP的核心逻辑是在AnnotationAwareAspectJAutoProxyCreator类里面实现,那么我们先来看看这个类的层次关系

    这个类实现了BeanPostProcessor接口,那就意味着这个类在spring加载实例化前会调用postProcessAfterInitialization方法,对于AOP的逻辑也是由此开始的。

    时序图

    流程说明

    1)spring 容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization()这个方法,然后接下来是调用wrapIfNecessary方法。

    /** 
     * Create a proxy with the configured interceptors if the bean is 
     * identified as one to proxy by the subclass. 
     * @see #getAdvicesAndAdvisorsForBean 
     */  
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
        if (bean != null) {  
            Object cacheKey = getCacheKey(bean.getClass(), beanName);  
            if (!this.earlyProxyReferences.containsKey(cacheKey)) {  
                return wrapIfNecessary(bean, beanName, cacheKey);  
            }  
        }  
        return bean;  
    } 

    2)进入wrapIfNecessary方法后,我们直接看重点实现逻辑的方法getAdvicesAndAdvisorsForBean,这个方法会提取当前bean 的所有增强方法,然后获取到适合的当前bean 的增强方法,然后对增强方法进行排序,最后返回

    /** 
         * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. 
         * @param bean the raw bean instance 
         * @param beanName the name of the bean 
         * @param cacheKey the cache key for metadata access 
         * @return a proxy wrapping the bean, or the raw bean instance as-is 
         */  
        protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {  
            if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {  
                return bean;  
            }  
            if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {  
                return bean;  
            }  
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {  
                this.advisedBeans.put(cacheKey, Boolean.FALSE);  
                return bean;  
            }  
      
            // Create proxy if we have advice.    
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);  
            if (specificInterceptors != DO_NOT_PROXY) {  
                this.advisedBeans.put(cacheKey, Boolean.TRUE);  
                Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));  
                this.proxyTypes.put(cacheKey, proxy.getClass());  
                return proxy;  
            }  
      
            this.advisedBeans.put(cacheKey, Boolean.FALSE);  
            return bean;  
        } 

    3)获取到当前bean的增强方法后,便调用createProxy方法,创建代理。先创建代理工厂proxyFactory,然后获取当前bean 的增强器advisors,把当前获取到的增强器添加到代理工厂proxyFactory,然后设置当前的代理工的代理目标对象为当前bean,最后根据配置创建JDK的动态代理工厂,或者CGLIB的动态代理工厂,然后返回proxyFactory

    /** 
         * Create an AOP proxy for the given bean. 
         * @param beanClass the class of the bean 
         * @param beanName the name of the bean 
         * @param specificInterceptors the set of interceptors that is 
         * specific to this bean (may be empty, but not null) 
         * @param targetSource the TargetSource for the proxy, 
         * already pre-configured to access the bean 
         * @return the AOP proxy for the bean 
         * @see #buildAdvisors 
         */  
        protected Object createProxy(  
                Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {  
      
            ProxyFactory proxyFactory = new ProxyFactory();  
            // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.  
            proxyFactory.copyFrom(this);  
      
            if (!shouldProxyTargetClass(beanClass, beanName)) {  
                // Must allow for introductions; can't just set interfaces to  
                // the target's interfaces only.  
                Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);  
                for (Class<?> targetInterface : targetInterfaces) {  
                    proxyFactory.addInterface(targetInterface);  
                }  
            }  
      
            Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);  
            for (Advisor advisor : advisors) {  
                proxyFactory.addAdvisor(advisor);  
            }  
      
            proxyFactory.<strong>setTargetSource</strong>(targetSource);  
            customizeProxyFactory(proxyFactory);  
      
            proxyFactory.setFrozen(this.freezeProxy);  
            if (advisorsPreFiltered()) {  
                proxyFactory.setPreFiltered(true);  
            }  
      
            return proxyFactory.getProxy(this.proxyClassLoader);  
        }  
    

    AOP动态代理执行

    关于AOP的动态代理执行,有两种主要的方式JDK的动态代理和CGLIB的动态代理,接下来,我们先来看看AOP动态代理的实现选择方式,先上核心实现代码:

    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);  
            }  
            return CglibProxyFactory.createCglibProxy(config);  
        }  
        else {  
            return new JdkDynamicAopProxy(config);  
        }  
    } 

    Spring JDK动态代理实现


    在上面的第三步骤说道或根据用户的配置(例如是否配置了 proxyTargetClass属性为true),选择创建的代理类型,这个的代理类型分两种实现,都是比较高效的,下面根据JDK的动态代理来说明AOP的执行,也是先上JdkDynamicAopProxy的核心代码invoke方法:

    public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {  
           MethodInvocation invocation = null;  
           Object oldProxy = null;  
           boolean setProxyContext = false;  
       
           TargetSource targetSource = this.advised.targetSource;  
           Class targetClass = null;  
           Object target = null;  
       
           try {  
               //eqauls()方法,具目标对象未实现此方法  
               if (!this.equalsDefined && AopUtils.isEqualsMethod(method)){  
                    return (equals(args[0])? Boolean.TRUE : Boolean.FALSE);  
               }  
       
               //hashCode()方法,具目标对象未实现此方法  
               if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)){  
                    return newInteger(hashCode());  
               }  
       
               //Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知  
               if (!this.advised.opaque &&method.getDeclaringClass().isInterface()  
                        &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
                    // Service invocations onProxyConfig with the proxy config...  
                    return AopUtils.invokeJoinpointUsingReflection(this.advised,method, args);  
               }  
       
               Object retVal = null;  
       
               if (this.advised.exposeProxy) {  
                    // Make invocation available ifnecessary.  
                    oldProxy = AopContext.setCurrentProxy(proxy);  
                    setProxyContext = true;  
               }  
       
               //获得目标对象的类  
               target = targetSource.getTarget();  
               if (target != null) {  
                    targetClass = target.getClass();  
               }  
       
               //获取可以应用到此方法上的Interceptor列表  
               List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);  
       
               //如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)  
               if (chain.isEmpty()) {  
                    retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args);  
               } else {  
                    //创建MethodInvocation  
                    invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, 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. Notethat we can't help if the target sets  
                    // a reference to itself inanother returned object.  
                    retVal = proxy;  
               }  
               return retVal;  
           } finally {  
               if (target != null && !targetSource.isStatic()) {  
                    // Must have come fromTargetSource.  
                   targetSource.releaseTarget(target);  
               }  
               if (setProxyContext) {  
                    // Restore old proxy.  
                    AopContext.setCurrentProxy(oldProxy);  
               }  
           }  
        }  
    其实上面的注释也说的比较清楚,各个步骤执行的说明:
    1)获取拦截器
    2)判断拦截器链是否为空,如果是空的话直接调用切点方法
    3)如果拦截器不为空的话那么便创建ReflectiveMethodInvocation类,把拦截器方法都封装在里面,也就是执行 getInterceptorsAndDynamicInterceptionAdvice方法

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {  
                       MethodCacheKeycacheKey = new MethodCacheKey(method);  
                       List<Object>cached = this.methodCache.get(cacheKey);  
                       if(cached == null) {  
                                cached= this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
                                                   this,method, targetClass);  
                                this.methodCache.put(cacheKey,cached);  
                       }  
                       returncached;  
             }  

    4)其实实际的获取工作其实是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()这个方法来完成的,获取到的结果会被缓存,下面来分析下这个方法的实现:

    /** 
        * 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor, 
        * 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断 
        * 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回. 
        */  
        publicList getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) {  
           // This is somewhat tricky... we have to process introductions first,  
           // but we need to preserve order in the ultimate list.  
           List interceptorList = new ArrayList(config.getAdvisors().length);  
       
           //查看是否包含IntroductionAdvisor  
           boolean hasIntroductions = hasMatchingIntroductions(config,targetClass);  
       
           //这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor  
           AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();  
       
           Advisor[] advisors = config.getAdvisors();  
            for (int i = 0; i <advisors.length; i++) {  
               Advisor advisor = advisors[i];  
               if (advisor instanceof PointcutAdvisor) {  
                    // Add it conditionally.  
                    PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor;  
                    if(config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {  
                        //TODO: 这个地方这两个方法的位置可以互换下  
                        //将Advisor转化成Interceptor  
                        MethodInterceptor[]interceptors = registry.getInterceptors(advisor);  
       
                        //检查当前advisor的pointcut是否可以匹配当前方法  
                        MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher();  
       
                        if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) {  
                            if(mm.isRuntime()) {  
                                // Creating a newobject instance in the getInterceptors() method  
                                // isn't a problemas we normally cache created chains.  
                                for (intj = 0; j < interceptors.length; j++) {  
                                   interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],mm));  
                                }  
                            } else {  
                                interceptorList.addAll(Arrays.asList(interceptors));  
                            }  
                        }  
                    }  
               } else if (advisor instanceof IntroductionAdvisor){  
                    IntroductionAdvisor ia =(IntroductionAdvisor) advisor;  
                    if(config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {  
                        Interceptor[] interceptors= registry.getInterceptors(advisor);  
                        interceptorList.addAll(Arrays.asList(interceptors));  
                    }  
               } else {  
                    Interceptor[] interceptors =registry.getInterceptors(advisor);  
                    interceptorList.addAll(Arrays.asList(interceptors));  
               }  
           }  
           return interceptorList;  
    }  
    5)这个方法执行完成后,Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor.

    6)接下来货到invoke方法中的proceed方法 ,我们再看下得到的拦截器链是怎么起作用的,也就是proceed方法的执行过程

    public Object proceed() throws Throwable {  
           //  We start with an index of -1and increment early.  
           if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()- 1) {  
               //如果Interceptor执行完了,则执行joinPoint  
               return invokeJoinpoint();  
           }  
       
           Object interceptorOrInterceptionAdvice =  
               this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
             
           //如果要动态匹配joinPoint  
           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)) {  
                    //执行当前Intercetpor  
                    returndm.interceptor.invoke(this);  
               }  
               else {  
                    //动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor  
                    return proceed();  
               }  
           }  
           else {  
               // It's an interceptor, so we just invoke it: The pointcutwill have  
               // been evaluated statically before this object was constructed.  
               //执行当前Intercetpor  
               return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
           }  
    }  
    7)好了拦截器到这边就可以执行了,复杂的代理终于可以起到他的作用了

    Spring CGLIB动态代理实现

    由于CGLIB的动态代理代码量比较长,在这就不贴出来代码了,其实这两个代理的实现方式都差不多,都是创建方法调用链,不同的是jdk的动态代理创建的是
    ReflectiveMethodInvocation调用链,而cglib创建的是Cglib MethodInvocation

    展开全文
  • Spring AOP 实现原理

    万次阅读 多人点赞 2013-09-24 15:23:43
    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为...
  • spring AOP实现原理实例

    千次阅读 2019-03-25 19:46:56
    什么是AOP AOP的全称是Aspect Orient Programming,即面向切面编程。是对OOP(Object Orient Programming)的一种补充,战门用于处理一些具有横切性质的服务。常常用于日志输出、安全控制等。 优点: 1、降低模块...
  • AOP的意思就是面向切面编程。本文主要是通过梳理JDK中自带的反射机制,实现 AOP动态代理模式,这也是Spring AOP实现原理
  • springAOP实现原理

    2017-04-14 16:43:26
    springAOP实现原理 AOP使用场景 AOP用来封装横切关注点,具体可以在下面的场景中使用:   Authentication 权限 Caching 缓存 Context passing 内容传递 Error handling 错误处理 Lazy loading 懒加载 ...
  • Spring AOPSpring AOP 实现原理

    千次阅读 2018-03-28 23:01:56
    一、为什么会出现AOP 一个场景 把大象装进冰箱分三步: (1)、打开冰箱 (2)、把大象装进冰箱 (3)、关上冰箱 把老虎装进冰箱分三步: (1)、打开冰箱 (2)、把老虎装进冰箱 (3)、关上冰箱 如果把...
  • 2 如何使用Spring AOP 可以通过配置文件或者编程的方式来使用Spring AOP。 ★ 通过配置xml(四种方式): 配置ProxyFactoryBean,显式地设置advisors, advice, target等 配置AutoProxyCreator,这种方式下,...
  • 本文我们通过Spring AOP和Java的自定义注解来实现日志的插入功能,非常不错,具有一定的参考借鉴价值,需要的朋友一起看看吧
  • AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。本文给大家介绍Springaop实现原理,感兴趣的朋友一起学习吧
  • AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译...
  • springAOP实现原理是什么?想了解一下,希望高手解答一下
  • Java面试题(四) - SpringAOP原理

    千次阅读 2019-03-20 10:58:16
    昨天进行的面试,被问到了SpringAOP原理问题,我当时只知道是通过动态代理实现的,其余的一脸懵逼状态。 问:请说一下SpringAOP原理。 答:SpringAOP是通过动态代理来实现的。 问:你说的动态代理是JDK的动态...
  • 例如:委托中介为自己找房子,或者房东委托中介替他把房子租出去。都是代理模式。
  • Spring--Spring AOP 实现原理与 CGLIB 应用

    千次阅读 2016-03-30 17:21:30
    AOP(Aspect Orient Programming),也就是面向方面编程,作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一
  • Spring AOP 实现机制和原理详解

    千次阅读 2017-01-05 10:34:37
    (1)AOP的各种实现 在编译器修改源代码、在运行期字节码加载前修改字节码或字节码加载后动态创建代理类的字节码。以下是各种实现机制的比较:   类别分为静态AOP(包括静态织入)和动态AOP(包括动态代理...
  • 灵魂画手图解Spring AOP实现原理

    千次阅读 多人点赞 2020-04-06 22:26:58
    本篇旨在让读者对Spring AOP实现原理有一个宏观上的认识,因此会丢失一些细节,具体实现参考:老实人Spring源码目录 阅读本篇文章前,希望读者对Spring Ioc以及Spring AOP的使用(@Aspect)由一定了解,话不多说,直接...
  • 完全读懂Spring框架之AOP实现原理

    千次阅读 2018-12-24 19:13:30
    深入分析Spring框架中AOP与动态代理的整合原理 从本文可以了解到什么 Spring的核心之一AOP具体是如何实现Spring AOP使用了哪些动态代理方式 如何使用Spring AOP创建代理对象 Spring有哪些代理切入方式,如何增加...
  • spring AOP实现原理(动态代理)

    千次阅读 2017-12-05 20:42:52
    看了很多aop原理和例子,都解释的太抽象,不容易理解,总结来说springaop主要是靠通知的形式实现的动态代理,在配置文件中配置或者使用注解,在对象使用时加入通用的功能,增加类的功能,下面这篇文章是我看到...
  • Spring AOP实现原理及应用场景(通过动态代理)
  • 揭秘spring aop底层原理实现

    千次阅读 2020-06-10 13:16:29
    相信每天工作都要用spring框架的大家一定使用过spring aopaop的概念是面向切面编程,相对与传统的面向对象编程oop,aop更关注的是横向的逻辑,比如说一个大型系统中的日志记录,异常处理,性能监控等等,都是各个...
  • 面试题--对于Spring Aop原理的理解

    千次阅读 2019-03-16 13:39:22
    这段时间对于Spring中的Aop原理做了一些了解,整理了一下大概分为以下几点,aop是什么以及aop实现原理,aop中常用的术语以及代理方式等等: 1.什么是 aop? aop是面向切面编程,不同于java原始的oop是面向对象编程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,009
精华内容 30,003
关键字:

springaop实现原理

spring 订阅