Spring技术内幕:Spring AOP的实现原理(三)
生成SingleTon代理对象在getSingleTonInstance方法中完毕,这种方法时ProxyFactoryBean生成AopProxy对象的入口。代理对象会封装对target目标对象的调用。也就是说针对target对象的方法调用行为会被这里生成的代理对象所拦截。
详细的生成过程是首先读取ProxyFactoryBean配置,为生成代理对象做好准备。Spring通过AopProxy类来详细生成代理对象。对于getSingleTonInstance方法中生成代理对象的步骤例如以下:
/**
     * Return the singleton instance of this class's proxy object,
     * lazily creating it if it hasn't been created already.
     * @return the shared singleton proxy
     */
    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.targetSource = freshTargetSource();
            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
                // Rely on AOP infrastructure to tell us what interfaces to proxy.
                // 依据AOP框架来推断须要代理的接口
                Class targetClass = getTargetClass();
                if (targetClass == null) {
                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
                }
                // 这里设置代理对象的接口
                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
            }
            // Initialize the shared singleton instance.
            super.setFrozen(this.freezeProxy);
            // 这里会使用ProxyFactoryBean来生成须要的proxy对象
            this.singletonInstance = getProxy(createAopProxy());
        }
        return this.singletonInstance;
    }
/**
     * Return the proxy object to expose.
     * <p>The default implementation uses a {@code getProxy} call with
     * the factory's bean class loader. Can be overridden to specify a
     * custom class loader.
     * @param aopProxy the prepared AopProxy instance to get the proxy from
     * @return the proxy object to expose
     * @see AopProxy#getProxy(ClassLoader)
     */
    protected Object getProxy(AopProxy aopProxy) {
        return aopProxy.getProxy(this.proxyClassLoader);
    }
这里出现了AopProxy对象类型,Spring利用AOPProxy接口类把AOP代理对象的实现与框架其它部分有效隔离开来。
AopProxy接口有两个子类实现,一个Cglib2AopProxy,还有一个是JdkDynamicProxy。 
详细代理对象的生成是在ProxyFactoryBean的基类AdvisedSupport中实现,借助AopProxyFactory完毕,这个对象要么从JDK中生成,要么借助CGLIB获得。
以下看看ProxyCreatorSupport中是怎样生成代理对象的。
    /**
     * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
     * create an AOP proxy with {@code this} as an argument.
     */
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        // 通过AopProxyFactory取得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
        return getAopProxyFactory().createAopProxy(this);
    }
AopProxy代理对象的生成有两种方式。假设目标对象是接口类使用JDK来生成,否则Spring会使用CGLIB来生成目标的代理对象。
以下看看在DefaultAopProxyFactory是怎样生成AopProxy目标代理对象的:
    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);
        }
    }
在AopProxy代理对象的生成过程中。首先要从AdviseSupport对象中取得配置的目标对象。AOP完毕的是切面应用对目标应用对象的增强。假设这里没有配置目标对象会直接抛出异常。一般而言,默认方式是使用JDK来产生AopProxy代理对象,但假设配置的目标对象不是接口类的实现,会使用CGLIB来产生AopProxy代理对象;在使用CGLIB来产生AopProxy代理对象时,由于CGLIB是第三方类库,本身不在JDK基类库中,全部须要在classPath中正确配置,以便可以载入和利用。在Spring中。使用JDK和CGLIB来生成AopProxy代理对象的工作,是由JdkDynamicAopProxy和CglibProxyFactory来完毕。
4、JDK生成AopProxy对象(接口实现类) 
通过上面我们已经知道生成AopProxy对象有两种方式,以下看下类图: 
 
我们先看下JdkDynamicAopProxy是怎样生成AopProxy对象的:
    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);
        // 调用JDK生成Proxy
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
5、CGLIB生成AopProxy对象(非接口实现类)
    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);
            // Configure CGLIB Enhancer...
            // 来自advised的IOC配置。比方使用AOP的DynamicAdvisedInterceptor
            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 MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
            enhancer.setInterceptDuringConstruction(false);
            // 通过设置DynamicAdvisedInterceptor拦截器来完毕AOP功能,getCallBacks方法例如以下:
            // Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised)
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
            enhancer.setCallbacks(callbacks);
            // Generate the proxy class and create a proxy instance.
            Object proxy;
            if (this.constructorArgs != null) {
                proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
            }
            else {
                proxy = enhancer.create();
            }
            return proxy;
        }
        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);
        }
    }
四、Spring AOP拦截器调用的实现 
1、设计原理 
在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完毕的。 
假设使用JDK的Proxy来生成代理对象,那么须要InvocationHandler来设置拦截器回调,而假设使用CGLIB来生成代理对象。通过DynamicAdvisedInterceptor来完毕回调。 
2、JdkDynamicAopProxy的invoke拦截 
在JDKDynamicAopProxy生成代理对象时,他的AopProxy代理对象生成调用:
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
this指的是InvocationHandler对象,InvocationHandler是JDK定义反射类的一个接口。这个接口定义了invoke方法,此方法为回调方法。
通过invoke的详细实现。来完毕对目标对象方法调用的拦截器或者功能增强工作。
在这种方法中。包括一个完整的拦截器链对目标对象的拦截过程。比方获取拦截器链中的拦截器进行配置。逐个执行拦截器链里的拦截器增强,知道最后的目标对象方法的执行。以下看下invoke的源代码
    /**
     * Implementation of {@code InvocationHandler.invoke}.
     * <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 {
            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.
            // 假设没有拦截器直接调用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.
            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);
            }
        }
    }
3、CglibAopProxy的intercept拦截器 
使用CglibAopProxy生成AopProxy对象时候。对于AOP拦截器调用。回调的是DynamicAdvisedInterceptor对象生成的。
回调的方法时intercept,以下看看回调方法的源代码:
        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 null. 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 = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null) {
                    releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
Spring技术内幕:Spring AOP的实现原理(三)的更多相关文章
- Spring技术内幕总结 - AOP概述
		
AOP是Aspect-Oriented Programming(面向方面/切面编程)的简称.Aspect是一种新的模块化机制,用来描述分散在对象.类或函数中的横切关注点.分离关注点使解决特定领域问题的 ...
 - Spring技术内幕:SpringIOC原理学习总结
		
前一段时候我把Spring技术内幕的关于IOC原理一章看完,感觉代码太多,不好掌握,我特意又各方搜集了一些关于IOC原理的资料,特加深一下印象,以便真正掌握IOC的原理. IOC的思想是:Spring ...
 - Spring技术内幕:设计理念和整体架构概述(转)
		
程序员都很崇拜技术大神,很大一部分是因为他们发现和解决问题的能力,特别是线上出现紧急问题时,总是能够快速定位和解决. 一方面,他们有深厚的技术基础,对应用的技术知其所以然,另一方面,在采坑的过程中不断 ...
 - 《spring技术内幕》读书笔记(1)——什么是POJO模式
		
今天在看<spring技术内幕>,第一章中多次提到了使用POJO来完成开发,就百度了一下,在此保留 1. 什么是POJO POJO的名称有多种,pure old java obje ...
 - 深入探索spring技术内幕(一): spring概述
		
一.Spring是什么? Spring是一个开源的控制反转 ( IoC ) 和面向切面 ( AOP ) 的容器框架, 它的主要目的是简化企业开发. 二.控制反转(IoC) 控制反转: 所谓的控制反转就 ...
 - 《Spring技术内幕》笔记-Spring的设计理念和总体架构
		
1.Spring的主要子项目: -1.Spring Framework(Core):Spring项目的核心.提供IoC,AOP,MVC等核心功能. -2.Spring Web Flow ...
 - Spring技术内幕:Spring AOP的实现原理(二)
		
**二.AOP的设计与实现 1.JVM的动态代理特性** 在Spring AOP实现中, 使用的核心技术时动态代理.而这样的动态代理实际上是JDK的一个特性.通过JDK的动态代理特性,能够为随意Jav ...
 - Spring技术内幕:Spring AOP的实现原理(一)
		
一.SpringAOP的概述 1.AOP概念 AOP是Aspect-Oriented Programming(面向切面编程)的简称.维基百科的解释例如以下: Aspect是一种新的模块化机制,用来描写 ...
 - Spring技术内幕:Spring AOP的实现原理(五)
		
7.Advice通知的实现 AopProxy代理对象生成时,其拦截器也一并生成.以下我们来分析下Aop是怎样对目标对象进行增强的.在为AopProxy配置拦截器的实现中,有一个取得拦截器配置过程,这个 ...
 
随机推荐
- Java源代码编译过程
			
编译其本质是将一种语言规范转换成另一种语言规范,即将Java语言规范转换为JVM虚拟机语言规范.结果就是.java文件到.class文件. 对于C/C++编译直接将高级语言转换为机器语言,Java ...
 - insert into table(key)value('value') on duplicate key update key=value
			
MYSQL篇 新增如果unique索引字段重复,则更新: insert into mg_user(key,key2,key3)value('value','value2','value3') on d ...
 - XCode6 ,iOS之PCH文件配置
			
1: 创建PCH文件 NewFile-->Other中的PCH File-->Next-->Create 2:配置PCH文件 项目中的TARGETS-->Build Setti ...
 - uva10392 Factoring Large Numbers
			
uva10392 Factoring Large Numbers 本文涉及的知识点是,使用线性筛选法得到素数表. Table of Contents 1 题目 2 思路 3 参考 1 题目 ===== ...
 - java 多线程处理一个list的集合
			
原文:http://blog.csdn.net/jenny8080/article/details/52100312 import java.util.ArrayList; import java.u ...
 - THttpClientSocket token验证
			
THttpClientSocket uses SynCrtSock非WINHTTP.DLL里面的控件,可以用于手机端. function Client(const SQL: RawUTF8): Raw ...
 - [Linux]   Linux smaps接口文件结构
			
在Linux内核 2.6.16中引入了一个系统内存接口特性,这个接口位于/proc/$pid/目录下的smaps文件中 ,一看内容发现是进程内存映像信息,比同一目录下的maps文件更详细些. 400d ...
 - 19个三维GIS软件对比
			
19个三维GIS软件对比 麦豆科研技术中心 days ago 我国GIS经过三十多年的发展,理论和技术日趋成熟,在传统二维GIS已不能满足应用需求的情况下,三维GIS应运而生,并成为GIS的重要发展方 ...
 - Gulp新手入门教程
			
Gulp 是一个自动化工具,前端开发者可以使用它来处理常见任务: 搭建web服务器 文件保存时自动重载浏览器 使用预处理器如Sass.LESS 优化资源,比如压缩CSS.JavaScript.压缩图片 ...
 - 较详细的介绍JNI
			
JNI其实是Java Native Interface的简称,也就是java本地接口.它提供了若干的API实现了和Java和其他语言的通信(主要是C&C++).也许不少人觉得Java已经足够强 ...