Spring AOP源码解析:二:代理对象的创建

目录:SpringAOP原理解析:

  1. 获取增强器Advisor
  2. 代理对象的创建
  3. 代理对象的执行

一、关键类介绍

MethodInterceptor: aop联盟中的一个接口,用于拦截方法调用的。
Advised:实现类有ProxyFactory: 记录了创建AOP代理对象的配置信息,核心是记录了该代理对象对应Advisor列表。同时还记录了一个AdvisorChainFactory对象,用来根据Advised和被代理的方法和类,来获取一个MethodInterceptor链。
TargetSource :记录了被代理的对象的相关信息,分为Static和非Static,代表了每次获取代理对象时是否返回同一个对象。
JdkDynamicAopProxy: 当采用JDK动态代理时,负责生成代理对象的类
CglibAopProxy: 采用cglib代理时,负责生成代理对象的类。

众所周知,Spring AOP代理的方式有2种,JDK的动态代理和Cglib的代理,前者必须实现接口,后者可以通过继承的方式实现。

二、代理对象创建流程

  1. 使用Advisor等参数构造一个ProxyFactory,不清楚Advisor的可以参考上一篇Advisor获取流程
  2. 根据条件及配置获取对应的AopProxy对象,如JdkDynamicAopProxy和CglibAopProxy,关键是将Advisor设置到对应的AopProxy对象中
  3. 调用AopProxy对象的getProxy方法生成代理对象。
  4. 当使用CglibAopProxy代理时,会将Advisor列表封装成一个MethodIntercept对象,设置到回调中,然后通过intercept方法进行拦截。当使用JdkDynamicAopProxy代理时,会使用InvocationHandler来进行拦截,JdkDynamicAopProxy本身就实现了InvocationHandler接口。

先看一段代码,AbstractAutoProxyCreator类,createProxy方法

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		// 通过ProxyFactory来创建代理对象。
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		// 由于获取的specificInterceptors不一定全部都是Advisor类,所以要处理一下,
		// 如果本身就是Advisor的话旧不做处理
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		// 要设置增强
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		
		return proxyFactory.getProxy(getProxyClassLoader());
	}

从上面代码我们看到了ProxyFactory这个类是创建代理对象的核心。
在这里插入图片描述
首先看Advised接口,官方文档说明,存储了一些关于AOP代理工厂的一些配置,包括拦截器和增强代理接口等等。

  • Interface to be implemented by classes that hold the configuration
  • of a factory of AOP proxies. This configuration includes the
  • Interceptors and other advice, Advisors, and the proxied interfaces.

然后看看ProxyFactory的功能,就是生成一个代理对象。然后看ProxyFactory
的父类ProxyCreatorSupport,这里有一个属性AopProxyFactory,这里AopProxyFactory负责生成AopProxy类。然后AopProxy类生成代理对象。
然后看到AdvisedSupport有一个AdvisorChainFactory,这个是用来生成代理的拦截器的,可以想到,我们生成的代理对象中可以会依赖这个。然后还保存了所有的增强Advisors。它的实现类InstantiationModelAwarePointcutAdvisorImpl。
先看一下AopProxyFactory的默认实现DefaultAopProxyFactory,

@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	//根据配置来看是否使用JDK动态代理还是cglib代理。这里有两个配置项,config.isProxyTargetClass默认配置在AopAutoConfiguration类里。
		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() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

代理对象类型

CglibAopProxy

cglib代理的的基础流程,可以看到主要流程就是设置了父类,然后设置一个回调callback,这些callback实现了MethodInterceptor接口就可以拦截代理对象的方法调用了。

public class CglibProxy {

    public static void main(String[] arg) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MySqlServiceReal.class);
        enhancer.setCallback(new MethodInterceptorImpl());
        MySqlServiceReal demo =  (MySqlServiceReal)enhancer.create();
        demo.getName();

    }

    public static class MySqlServiceReal{

        public String getName() {
            System.out.println("execute something sql");
            saveName();
            return "sql result";
        }

        public void saveName() {
            System.out.println("save my name");
        }
    }



    private static class MethodInterceptorImpl implements MethodInterceptor {
        @Override
        public Object intercept(Object object,
                                Method method,
                                Object[] args,
                                MethodProxy methodProxy) throws Throwable {
            System.out.println("before");
            Object res = methodProxy.invokeSuper(object, args);
            System.out.println("After");
            return res;
        }
    }
}

跟踪SpringAop代码,我们来分析下cglib代理的AOP是如何将Advisor变成Callback设置到代理对象中的。
核心操作就是把Advisor列表封装成一个MethodInterceptor对象,从上面的例子可以看出,会通过MethodInterceptor的intercept进行拦截。

 private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
		// Parameters used for optimization choices...
		boolean exposeProxy = this.advised.isExposeProxy();
		boolean isFrozen = this.advised.isFrozen();
		// isStatic表示目标对象TargetSource是否每次getTarget返回的是同一个对象
		boolean isStatic = this.advised.getTargetSource().isStatic();

		// Choose an "aop" interceptor (used for AOP calls).
		// 1。把Advisor封装成一个callback
		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;
		// 2. 如果配置了暴露当前代理对象,则在创建目标方法拦截器时会在当前ThreadLocal变量中设置当前代理对象
		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());
    // 这里加入了7个拦截器,和AOP相关的就只有一个aopInterceptor
		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)
		};
    /*********************省略部分代码**************/
	}

JdkDynamicAopProxy

JDK动态代理很好理解,是通过InvocationHandler接口来拦截目标方法的执行的。JdkDynamicAopProxy这个类本身就实现了InvocationHandler接口来拦截方法调用。

参考文章:
https://my.oschina.net/guangshan/blog/1797461

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值