根据配置获取AopProxy
这个阶段对应的代码:
// 创建AopProxy使用了简单工厂模式
AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
//通过AopProxy工厂获取AopProxy对象
AopProxy aopProxy = aopProxyFactory.createAopProxy(advisedSupport);
此阶段会根据AdvisedSupport中配置信息,判断具体是采用cglib的方式还是采用jdk动态代理的方式获取代理对象,先看一下涉及到的一些类。
AopProxy接口
这个接口定义了一个方法,用来创建最终的代理对象,这个接口有2个实现类:
- CglibAopProxy:采用cglib的方式创建代理对象
- JkdDynamicAopProxy:采用jdk动态代理的方式创建代理对象
public interface AopProxy {
/**
* 创建一个新的代理对象
*/
Object getProxy();
/**
* 创建一个新的代理对象
*/
Object getProxy(@Nullable ClassLoader classLoader);
}
AopProxyFactory接口
通过名称就可以看出来,是一个工厂,负责创建AopProxy,使用的是简单工厂模式。
public interface AopProxyFactory {
/**
* 根据aop配置信息获取AopProxy对象
*/
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
DefaultAopProxyFactory类
AopProxyFactory接口的默认实现,代码比较简单,我们来细看一下:
/**
* 默认AopProxyFactory实现,创建CGLIB代理或JDK动态代理。
* 对于给定的AdvisedSupport实例,以下条件为真,则创建一个CGLIB代理:
* optimize = true
* proxyTargetClass = true
* 未指定代理接口
* 通常,指定proxyTargetClass来强制执行CGLIB代理,或者指定一个或多个接口来使用JDK动态代理。
*/
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// optimize==true || proxyTargetClass 为true || 配置中没有需要代理的接口
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动态代理创建代理类,则采用JdkDynamicAopProxy的方式,否则采用cglib代理的方式
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
//采用jdk动态代理的方式
return new JdkDynamicAopProxy(config);
}
//采用cglib代理的方式
return new ObjenesisCglibAopProxy(config);
}
else {
//采用jdk动态代理的方式
return new JdkDynamicAopProxy(config);
}
}
/**
* 确定所提供的AdvisedSupport是否只指定了SpringProxy接口(或者根本没有指定代理接口)
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
代理创建阶段
到目前为止我们已经根据aop配置信息得到了AopProxy对象了,下面就可以调用AopProxy.getProxy方法获取代理对象了。
AopProxy.createAopProxy方法返回的结果有2种情况:
- JdkDynamicAopProxy:以jdk动态代理的方式创建代理
- ObjenesisCglibAopProxy:以cglib的方式创建动态代理
JdkDynamicAopProxy类
作用:采用jdk动态代理的方式创建代理对象,并处理代理对象的所有方法调用。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//代理的配置信息
private final AdvisedSupport advised;
//需要被代理的接口中是否定义了equals方法
private boolean equalsDefined;
//需要被代理的接口中是否定义了hashCode方法
private boolean hashCodeDefined;
//通过AdvisedSupport创建实例
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;
}
//生成一个代理对象
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
//生成一个代理对象
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//@0:根据advised的信息获取代理需要被代理的所有接口列表
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//查找被代理的接口中是否定义了equals、hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
/**
* 这个大家应该很熟悉吧,通过jdk动态代理创建代理对象,注意最后一个参数是this
* 表示当前类,当前类是InvocationHandler类型的,当调用代理对象的任何方法的时候
* 都会被被当前类的 invoke 方法处理
*/
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//判断需要代理的接口中是否定义了这几个方法(equals、hashCode)
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
//获取接口中定义的方法
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
//是否是equals方法
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
//是否是hashCode方法
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
//如果发现这2个方法都定义了,结束循环查找
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
// 这个方法比较关键了,当在程序中调用代理对象的任何方法,最终都会被下面这个invoke方法处理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//旧的代理对象
Object oldProxy = null;
//用来标记是否需要将代理对象暴露在ThreadLocal中
boolean setProxyContext = false;
//获取目标源
TargetSource targetSource = this.advised.targetSource;
//目标对象
Object target = null;
//下面进入代理方法的处理阶段
try {
// 处理equals方法:被代理的接口中没有定义equals方法 && 当前调用是equals方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 直接调用当前类中的equals方法
return equals(args[0]);
}
// 处理hashCode方法:被代理的接口中没有定义hashCode方法 && 当前调用是hashCode方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 直接调用当前类中的hashCode方法
return hashCode();
}
/**
* 方法来源于 DecoratingProxy 接口,这个接口中定义了一个方法
* 用来获取原始的被代理的目标类,主要是用在嵌套代理的情况下(所谓嵌套代理:代理对象又被作为目标对象进行了代理)
*/
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// 调用AopProxyUtils工具类的方法,内部通过循环遍历的方式,找到最原始的被代理的目标类
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 方法来源于 Advised 接口,代理对象默认情况下会实现 Advised 接口,可以通过代理对象来动态向代理对象中添加通知等
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// this.advised是AdvisedSupport类型的,AdvisedSupport实现了Advised接口中的所有方法
// 所以最终通过通过反射方式交给this.advised来响应当前调用
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 用来记录方法返回值
Object retVal;
//是否需要在threadLocal中暴露代理对象
if (this.advised.exposeProxy) {
// 将代理对象暴露在上线文中,即暴露在threadLocal中,那么在当前线程中可以通过静态方法
// AopContext#currentProxy获取当前被暴露的代理对象,这个是非常有用的,稍后用案例来讲解,瞬间就会明白
oldProxy = AopContext.setCurrentProxy(proxy);
// 将setProxyContext标记为true
setProxyContext = true;
}
// 通过目标源获取目标对象
target = targetSource.getTarget();
// 获取目标对象类型
Class<?> targetClass = (target != null ? target.getClass() : null);
// @1:获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 拦截器链为空的情况下,表示这个方法上面没有找到任何增强的通知,那么会直接通过反射直接调用目标对象
if (chain.isEmpty()) {
// 获取方法请求的参数(有时候方法中有可变参数,所谓可变参数就是带有省略号(...)这种格式的参数,传入的参数类型和这种类型不一样的时候,会通过下面的adaptArgumentsIfNecessary方法进行转换)
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//通过反射直接调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建一个方法调用器(包含了代理对象、目标对象、调用的方法、参数、目标类型、方法拦截器链)
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// @2:通过拦截器链一个个调用最终到目标方法的调用
retVal = invocation.proceed();
}
// 下面会根据方法返回值的类型,做一些处理,比如方法返回的类型为自己,则最后需要将返回值置为代理对象
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 将返回值设置为代理对象
retVal = proxy;
}
// 方法的返回值类型returnType为原始类型(即int、byte、double等这种类型的) && retVal为null,
// 此时如果将null转换为原始类型会报错,所以此处直接抛出异常
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 {
// 目标对象不为null && 目标源不是静态的
//所谓静态的,你可以理解为是否是单例的
// isStatic为true,表示目标对象是单例的,同一个代理对象中所有方法共享一个目标对象
// isStatic为false的时候,通常每次调用代理的方法,target对象是不一样的,所以方法调用万之后需要进行释放,可能有些资源清理,连接的关闭等操作
if (target != null && !targetSource.isStatic()) {
// 必须释放来自TargetSource中的目标对象
targetSource.releaseTarget(target);
}
// setProxyContext为ture
if (setProxyContext) {
// 需要将旧的代理再放回到上线文中
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
@0:completeProxiedInterfaces方法
@0处的代码如下,根据代理配置信息,获取需要被代理的所有接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
AopProxyUtils.completeProxiedInterfaces
方法源码如下:
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
//获取代理配置中需要被代理的接口
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
// 需要被代理的接口数量为0
if (specifiedInterfaces.length == 0) {
// 获取需要被代理的目标类型
Class<?> targetClass = advised.getTargetClass();
//目标类型不为空
if (targetClass != null) {
//目标类型为接口
if (targetClass.isInterface()) {
//将其添加到需要代理的接口中
advised.setInterfaces(targetClass);
}
// 目标类型为jdk动态代理创建的代理对象
else if (Proxy.isProxyClass(targetClass)) {
// 获取目标类型上的所有接口,将其添加到需要被代理的接口中
advised.setInterfaces(targetClass.getInterfaces());
}
//再次获取代理配置中需要被代理的接口
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
//判断SpringProxy接口是否已经在被代理的接口中
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
//判断Advised接口是否已经在被代理的接口中
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
//判断DecoratingProxy接口是否已经在被代理的接口中
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
//一个计数器,会根据上面三个boolean值做递增
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
if (addDecoratingProxy) {
nonUserIfcCount++;
}
// 下面就是构建所有需要被代理的接口
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
return proxiedInterfaces;
}
上面的方法执行完毕之后,会得到一个被代理的接口列表,默认情况下会得到下面的一个列表:
[开发者硬编码指定的需要被代理的接口列表,SpringProxy,Advised,DecoratingProxy]
最终创建出来的代理对象,默认会实现上面列的所有接口,后面3个接口是aop中自动给我们加上的。
@1:getInterceptorsAndDynamicInterceptionAdvice
这个方法位于AdvisedSupport
中,根据方法和目标类型获取方法上面匹配的拦截器链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//会先尝试从还中获取,如果获取不到,会从advisorChainFactory中获取,然后将其丢到缓存中
MethodCacheKey cacheKey = 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);
}
return cached;
}
从advisorChainFactory中获取拦截器链稍后细说,我们把这个阶段叫做连接器链的获取阶段。
@2:ReflectiveMethodInvocation.proceed()
这个是一次会调用拦截器链,最终会调用到目标方法,获得目标方法的返回值,里面的细节见后面的代理方法调用处理阶段
JdkDynamicAopProxy小结
- 被创建的代理对象默认会实现
SpringProxy,Advised,DecoratingProxy
3个接口 SpringProxy
这个接口中没有任何方法,只是起一个标记作用,用来标记代理对象是使用spring aop创建的- 代理对象默认都会实现
Advised
接口,所以可以通过这个接口动态变更代理对象中的通知 DecoratingProxy
接口中定义了一个方法getDecoratedClass
,用来获取被代理的原始目标对象的类型
下面来看另外一个类:ObjenesisCglibAopProxy
,这个继承了CglibAopProxy
,大部分逻辑都在CglibAopProxy
中,所以我们主要看CglibAopProxy
中代码。
CglibAopProxy类
作用:采用cglib代理的方式创建代理对象,并处理代理对象的所有方法调用。
以getProxy
方法为入口,通过方法一个个来解说。
public Object getProxy(@Nullable ClassLoader classLoader) {
// 获取被代理的类
Class<?> rootClass = this.advised.getTargetClass();
// 代理对象的父类(cglib是采用继承的方式是创建代理对象的,所以将被代理的类作为代理对象的父类)
Class<?> proxySuperClass = rootClass;
// 判断被代理的类是不是cglib创建的类,如果是cblib创建的类,会将其父类作为被代理的类
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
//添加需要被代理的接口
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 开始cglib创建代理,这个大家对cglib比较熟悉的一看就懂
Enhancer enhancer = createEnhancer();
// 设置被代理的父类
enhancer.setSuperclass(proxySuperClass);
// 设置被代理的接口[开发者硬编码指定的需要被代理的接口列表,SpringProxy,Advised],这个比jdk动态代理的方式少了一个DecoratingProxy接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
// 设置代理类类名生成策略
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// 设置字节码的生成策略
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// @1:获取Callback列表,这个稍后详解
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// @2:设置CallbackFilter,CallbackFilter内部会判断被代理对象中的方法最终会被callbacks列表中的那个Callback来处理
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 获取代理对象(内部会先创建代理类,然后会根据代理类生成一个代理对象)
return createProxyClassAndInstance(enhancer, callbacks);
}
上面方法中有2个点比较难,需要说明,分别是@1:getCallbacks
方法和@2:创建ProxyCallbackFilter
对象
@1:getCallbacks方法
通过被代理的类来获取Callback列表,Callback是用来处理代理对象的方法调用的,代理对象中可能有很多方法,每个方法可能采用不同的处理方式,所以会有多个Callback
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 是否需要将代理暴露在threadLocal中
boolean exposeProxy = this.advised.isExposeProxy();
// 配置是否是冻结的
boolean isFrozen = this.advised.isFrozen();
// 被代理的目标对象是否是动态的(是否是单例的)
boolean isStatic = this.advised.getTargetSource().isStatic();
// 当方法上有需要执行的拦截器的时候,会用这个来处理
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 当方法上没有需要执行的拦截器的时候,会使用targetInterceptor来处理,内部会通过反射直接调用目标对象的方法
Callback targetInterceptor;
/**
* 这块根据是否需要暴露代理到threadLocal中以及目标对象是否是动态的,会创建不同的Callback
* isStatic为true的时候,同一个代理的不同方法可能都是新的目标对象,所以当代理方法执行完毕之后,需要对目标对象进行释放
*/
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()));
}
// targetDispatcher会直接调用目标方法
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // 处理匹配到拦截器的方法
targetInterceptor, // 处理未匹配到拦截器的方法
new SerializableNoOp(),
targetDispatcher, // 处理未匹配到拦截器的方法,和targetInterceptor有何不同呢?目标方法如果返回值的结果是目标对象类型的,会使用 targetInterceptor 处理,内部会返回代理对象
this.advisedDispatcher, // 处理Advised接口中定义的方法
new EqualsInterceptor(this.advised), // 处理equals方法
new HashCodeInterceptor(this.advised) // 处理hashCode方法
};
Callback[] callbacks;
// 如果被代理的对象是单例的 && 配置是冻结的,此时会进行优化,怎么优化呢?
// 配置冻结的情况下,生成好的代理中通知是无法修改的,所以可以提前将每个方法对应的拦截器链找到给缓存起来
// 调用方法的时候,就直接从缓存中可以拿到方法对应的缓存信息,效率会高一些
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length);
// 获取每个方法的调用链,然后给缓存在fixedInterceptorMap中
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(method, x);
}
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;
}
@2:创建ProxyCallbackFilter对象
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
这块重点在于ProxyCallbackFilter
中的accept
方法,这个方法会根据目标方法,获取目标方法最后会让callbacks
列表中的哪个Callback
处理,大家可以看一下源码,比较简单。
上面getCallbacks
方法中涉及到了5个类如下:
- DynamicAdvisedInterceptor
- StaticUnadvisedExposedInterceptor
- StaticUnadvisedInterceptor
- DynamicUnadvisedInterceptor
- StaticDispatcher
主要来看第一个类,基本上代理对象中的大部分自定义的方法都会进入到这个类的intercept方法中进行处理,代码如下:
DynamicAdvisedInterceptor类:
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
//代理配置信息
private final AdvisedSupport advised;
//构造器,需要一个AdvisedSupport
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
//这个方法是关键,用来处理代理对象中方法的调用
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//被暴露在threadLocal中旧的代理对象
Object oldProxy = null;
//用来标记代理对象是否被暴露在threadLocal中
boolean setProxyContext = false;
//目标对象
Object target = null;
//目标源
TargetSource targetSource = this.advised.getTargetSource();
try {
//代理配置中是否需要将代理暴露在threadLocal中
if (this.advised.exposeProxy) {
//将代理对象暴露出去
oldProxy = AopContext.setCurrentProxy(proxy);
//将setProxyContext置为true
setProxyContext = true;
}
//获取目标对象(即被代理的对象)
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//@1:获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//记录方法返回值
Object retVal;
//拦截器链不为空 && 方法是public类型的
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
//获取方法调用参数
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 直接调用目标对象的方法
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 创建一个方法调用器(包含了代理对象、目标对象、调用的方法、参数、目标类型、方法拦截器链)
// @2:并执行方法调用器的processd()方法,此方法会一次执行方法调用链,最终会调用目标方法,获取返回结果
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// 处理方法返回结果:会根据方法返回值的类型,做一些处理,比如方法返回的类型为自己,则最后需要将返回值置为代理对象
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
// 目标对象不为null && 目标源不是静态的
//所谓静态的,你可以理解为是否是单例的
// isStatic为true,表示目标对象是单例的,同一个代理对象中所有方法共享一个目标对象
// isStatic为false的时候,通常每次调用代理的方法,target对象是不一样的,所以方法调用万之后需要进行释放,可能有些资源清理,连接的关闭等操作
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
// setProxyContext为ture
if (setProxyContext) {
// 需要将旧的代理再放回到上线文中
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
上面代码中2个重点:@1和@2
@1:获取当前方法的拦截器链,这个在JdkDynamicAopProxy的也有,稍后说。
@2:调用CglibMethodInvocation.proceed(),内部会一次调用方法拦截器链,最终会调用目标方法,获取目标方法返回值,这个稍后放在代理方法处理阶段详解。
下面来看一下方法拦截器链的获取。
方法拦截器链的获取
我们在创建代理的时候,增强的代码通常都放在Advise通知中,但是最终调用方法的时候,这些通知都会被转换为MethodInterceptor来执行,调用方法的过程中,需要先获取方法上匹配的所有方法拦截器链,然后依次执行,最终会调用到目标方法。
获取方法对应的拦截器链,对应下面这段代码
org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = 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);
}
return cached;
}
会调用DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
方法获取方法上匹配的拦截器链。
涉及到的类
AdvisorChainFactory接口
拦截器链工厂接口,定义了一个方法,用来获取方法匹配的拦截器链列表
public interface AdvisorChainFactory {
/**
* 获取方法匹配的拦截器链列表
* @param config:代理配置信息,里面包含了创建代理的所有信息,如:Advisor列表,此方法会从Advisor列表中找到和mehod匹配的
* @param targetClass:目标类
*/
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass);
}
DefaultAdvisorChainFactory类
AdvisorChainFactory接口的默认实现。
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 获取Advisor适配器注册器,前面我们有提到过一个知识点:所有的Advisor最终都会转换为MethodInterceptor类型的,
// 然后注册方法调用链去执行,AdvisorAdapterRegistry就是搞这个事情的,
// 其内部会将非MethodInterceptor类型通知通过适配器转换为MethodInterceptor类型
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//获取配置中的Advisor列表
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
//获取被调用方法所在类实际的类型
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
//遍历Advisor列表,找到和actualClass和方法匹配的所有方法拦截器(MethodInterceptor)链列表
for (Advisor advisor : advisors) {
//判断是否是PointcutAdvisor类型的,这种类型的匹配分为2个阶段,先看类是否匹配,然后再看方法是否匹配
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 如果isPreFiltered为ture,表示类以及匹配过,不需要看类是否匹配了
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
//方法是否匹配
match = mm.matches(method, actualClass);
}
//方法匹配
if (match) {
// 通过AdvisorAdapterRegistry的getInterceptors将advisor转换为MethodInterceptor列表
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//方法是否动态匹配
if (mm.isRuntime()) {
//轮询连接器,将其包装为InterceptorAndDynamicMethodMatcher对象,后续方法调用的时候可以做动态匹配
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
}
下面来看AdvisorAdapterRegistry这个接口。
AdvisorAdapterRegistry接口
AdvisorAdapter注册器,AdvisorAdapter可以将Advisor中的Advice适配为MethodInterceptor
public interface AdvisorAdapterRegistry {
//将一个通知(Advice)包装为Advisor对象
Advisor wrap(Object advice) throws UnknownAdviceTypeException;
//根据Advisor获取方法MethodInterceptor列表
MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException;
//注册AdvisorAdapter,AdvisorAdapter可以将Advisor中的Advice适配为MethodInterceptor
void registerAdvisorAdapter(AdvisorAdapter adapter);
}
DefaultAdvisorAdapterRegistry类
AdvisorAdapterRegistry的默认实现,目前里面做的事情主要是将负责将前置通知,异常通知,后置通知转换为MethodInterceptor类型的,源码比较简单,大家看一下就懂了。
AdvisorAdapter接口
public interface AdvisorAdapter {
//判断这个适配器支持advice这个通知么
boolean supportsAdvice(Advice advice);
//获取advisor对应的MethodInterceptor
MethodInterceptor getInterceptor(Advisor advisor);
}
MethodBeforeAdviceAdapter类
适配MethodBeforeAdvice前置通知,负责将MethodBeforeAdvice类型的通知转换为MethodBeforeAdviceInterceptor类型的
MethodBeforeAdviceInterceptor类
将MethodBeforeAdvice通知适配为MethodInterceptor类型的
AfterReturningAdviceAdapter类
适配AfterReturningAdvice后置通知,负责将AfterReturningAdvice类型的通知转换为AfterReturningAdviceInterceptor类型的
AfterReturningAdviceInterceptor类
将AfterReturningAdvice通知适配为MethodInterceptor类型的
ThrowsAdviceAdapter类
适配ThrowsAdvice前置通知,负责将MethodBeforeAdvice类型的通知转换为MethodBeforeAdviceInterceptor类型的
ThrowsAdviceInterceptor类
将ThrowsAdvice通知适配为MethodInterceptor类型的
代理方法的调用过程(拦截器链的执行)
拦截器链执行过程
到目前,已经获取到代理对象,接着会开始使用这个代理对象,在代理对象上执行一些方法调用,此时会依次调用此方法上的所有MethodInterceptor,最终会调用到目标上对应的方法,执行过程如下图
jdk动态代理方式创建代理最终会调用ReflectiveMethodInvocation#proceed
方法。
cglib方式创建的代理最终会调用CglibAopProxy.CglibMethodInvocation#proceed
方法。
ProxyFactory简化代理的创建
上面代理的整个创建过程和使用过程还是挺负载的,spring在AdvisedSupport
类的基础上又添加2个子类
- ProxyCreatorSupport
- ProxyFactory
ProxyCreatorSupport用来对代理的创建提供支持,内部添加了AopProxyFactory对象的引用,将代理的创建过程给简化了。
ProxyFactory类继承了ProxyCreatorSupport,让创建代理的过程更简单了,如果采用硬编码的方式,通常我们会使用ProxyFactory来创建代理对象,代码只需要下面几行了
//通过spring提供的代理创建工厂来创建代理
ProxyFactory proxyFactory = new ProxyFactory();
//ProxyFactory继承了AdvisedSupport类,所以可以直接可以通过ProxyFactory来设置创建代理需要的参数
//为工厂指定目标对象
proxyFactory.setTarget(target);
//添加顾问
proxyFactory.addAdvisor(advisor);
//调用proxyFactory.getProxy();创建代理
Object proxy = proxyFactory.getProxy();
案例
案例1
这个案例主要看一下生成的代理对象的一些信息。
@Test
public void testAop6(){
ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method);
}
}));
//创建代理对象
Object proxy = proxyFactory.getProxy();
System.out.println("代理对象的类型:" + proxy.getClass());
System.out.println("代理对象的父类:" + proxy.getClass().getSuperclass());
System.out.println("代理对象实现的接口列表");
for (Class<?> cf : proxy.getClass().getInterfaces()) {
System.out.println(cf);
}
}
运行结果:
代理对象的类型:class com.spring.beanAOP1.FundsService$$EnhancerBySpringCGLIB$$d0bfcf3
代理对象的父类:class com.spring.beanAOP1.FundsService
代理对象实现的接口列表
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.cglib.proxy.Factory
案例2
有接口的情况默认会通过jdk动态代理的方式生成代理
public interface IService {
void say();
}
public class ServiceImpl implements IService {
@Override
public void say() {
System.out.println("say...");
}
}
@Test
public void testAop7() {
ServiceImpl impl = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(impl);
//设置接口
proxyFactory.setInterfaces(IService.class);
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method);
}
});
IService proxy = (IService) proxyFactory.getProxy();
System.out.println("代理对象的类型:" + proxy.getClass());
System.out.println("代理对象的父类:" + proxy.getClass().getSuperclass());
System.out.println("代理对象实现的接口列表");
for (Class<?> cf : proxy.getClass().getInterfaces()) {
System.out.println(cf);
}
//调用代理的方法
System.out.println("\n调用代理的方法");
proxy.say();
}
运行结果:
代理对象的类型:class com.sun.proxy.$Proxy4
代理对象的父类:class java.lang.reflect.Proxy
代理对象实现的接口列表
interface com.spring.beanAOP2.IService
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.core.DecoratingProxy
调用代理的方法
public abstract void com.spring.beanAOP2.IService.say()
say...
案例3:强制使用cglib代理
在案例2中加入下面代码,设置proxyTargetClass为true,会强制使用cglib代理
proxyFactory.setProxyTargetClass(true);
案例4:将代理暴露在threadLocal中
先来看一段代码:
public class Service1 {
public void m1(){
System.out.println("m1");
this.m2();
}
public void m2(){
System.out.println("m2");
}
}
测试:
@Test
public void testAop8(){
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new Service1());
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(String.format("进入%s方法",invocation.getMethod().getName()));
long startTime = System.nanoTime();
Object proceed = invocation.proceed();
long endTime = System.nanoTime();
System.out.println(endTime - startTime);
return proceed;
}
});
Service1 proxy = (Service1)proxyFactory.getProxy();
proxy.m1();
}
运行:
进入m1方法
m1
m2
6756129701
我们发现没有统计m2方法的耗时,为什么呢?
原因:m2方法是在m1方法中通过this的方式来调用的,this实际上指向的是上面代码中的new Service1()
对象。
那么我们如何能让此处的m2也能被增强,你需要通过代理来调用m2方法才可以,可以将代理对象暴露在threadLocal中,然后在m1方法中获取到threadLoca中的代理对象,通过代理对象来调用m2就可以了
然后进行修改:
- 配置代理创建时,将其暴露出去
proxyFactory.setExposeProxy(true);
- m1中调用m2的方法需要修改为
((Service1)AopContext.currentProxy()).m2();
运行结果:
进入m1方法
m1
进入m2方法
m2
方法m2耗时314700
方法m1耗时31416600
下一篇文章将深入详解介绍spring中如何将aop搞成自动化的