您的位置:首页 > 编程语言 > Java开发

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

2019-03-12 21:46 621 查看

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

从上面代码我们看到了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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: