• 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

     

    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();
    		}
    	}

     ProxyCreatorSupport

     

     

    protected final synchronized AopProxy createAopProxy() {
    		if (!this.active) {
    			activate();
    		}
    		return getAopProxyFactory().createAopProxy(this);
    	}

     DefaultAopProxyFactory

     

     

    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);
    		}
    	}

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

     

     

    UserMgr mgr = new UserMgrImpl();
    InvocationHandler h = new TransactionHandler(mgr);
    UserMgr u = (UserMgr) Proxy.newProxyInstance(UserMgr.class, h);

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

    public class Proxy implements java.io.Serializable {
      /** prefix for all proxy class names */
        private final static String proxyClassNamePrefix = "$Proxy";
      /**
         * the invocation handler for this proxy instance.
         * @serial
         */
        protected InvocationHandler h;
    }

     

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

     

    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 {
    		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.
    			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.
    		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);
    		}
    	}
    }

     ReflectiveMethodInvocation implements ProxyMethodInvocation extends MethodInvocation extends Invocation extends Joinpoint

    public Object proceed() throws Throwable {
    	//	We start with an index of -1 and increment early.
    	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)) {
    			return dm.interceptor.invoke(this);
    		}
    		else {
    			// Dynamic matching failed.
    			// Skip this interceptor and invoke the next in the chain.
    			return proceed();
    		}
    	}
    	else { // eg. ExposeInvocationInterceptor
    		// 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);
    	}
    }

     

    package org.aopalliance.intercept; // Aop联盟
    
    import java.lang.reflect.AccessibleObject;
    
    public interface Joinpoint {
        Object proceed() throws Throwable;
    
        Object getThis();
    
        AccessibleObject getStaticPart();
    }

     interceptor.invoker - eg. MethodBeforeAdviceInterceptor

    public Object invoke(MethodInvocation mi) throws Throwable {
    	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
    	return mi.proceed(); // 又回归到了上面的调用
    }

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

    public Object invoke(MethodInvocation mi) throws Throwable {
    	MethodInvocation oldInvocation = invocation.get();
    	invocation.set(mi);
    	try {
    		return mi.proceed();
    	}
    	finally {
    		invocation.set(oldInvocation);
    	}
    }

     

     Aop应用参考:

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

    二、方法性能监控

    package com.itlong.bjxizhan.support.web.service.monitor;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    /**
     * Created by shenhongxi on 2016/8/10.
     */
    @Aspect
    public class MonitorAspect {
    
        private String tagPrefix;
    
        @Around(
                value = "execution(* *(..)) && @annotation(monitor)",
                argNames = "pjp,monitor"
        )
        public Object doUmpLogging(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
            // String tag = monitor.tag();
            // boolean heart = monitor.heart();
            long start = System.currentTimeMillis();
            // record invocation (times)
            Object obj = null;
            try {
                obj = pjp.proceed();
            } catch (Exception e) {
                // record error
                throw e;
            } finally {
                long end = System.currentTimeMillis();
                // record time -> end - start
            }
            return obj;
        }
    
        public String getTagPrefix() {
            return tagPrefix;
        }
    
        public void setTagPrefix(String tagPrefix) {
            this.tagPrefix = tagPrefix;
        }
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
    public @interface Monitor {
        String DEFAULT_TAG_NAME = "@@USE_METHOD_NAME";
    
        String tag() default "@@USE_METHOD_NAME";
    
        String message() default "";
    
        boolean heart() default false;
    
    }

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

    京东技术
  • 相关阅读:
    0 Explore TreeView
    按钮颜色选择器
    颜色组合框
    Get Files from Directory
    05.0 图片
    WINAPI 变量(2861个)
    为字符串增加50个空格
    让DataGridView显示行号
    相对路径
    SpecialFolder
  • 原文地址:https://www.cnblogs.com/wely/p/6198736.html
Copyright © 2020-2023  润新知