深入分析 Spring 框架中 AOP 与动态代理的整合原理

2019 年 5 月 4 日 ImportNew

(给ImportNew加星标,提高Java技能)


转自:开源中国,

链接:my.oschina.net/guangshan/blog/1797461


Spring AOP动态代理支持的核心


1.jdk动态代理:java.lang.reflect.InvocationHandler


对应的方法拦截器:


public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
;


调用时使用method.invoke(Object, args)


该动态代理是基于接口的动态代理,所以并没有一个原始方法的调用过程,整个方法都是被拦截的。


2.通过cglib动态创建类进行动态代理。org.springframework.cglib.proxy包下的原生接口,同net.sf.cglib.proxy包下的接口,都是源自cglib库。Spring内部的cglib动态代理使用了这种方式。


对应的方法拦截器:


org.springframework.cglib.proxy.Callback、 org.springframework.cglib.proxy.MethodInterceptor


public interface MethodInterceptor extends Callback {
Object intercept(Object obj, Method m, Object[] args, MethodProxy mp) throws Throwable
}


调用时,使用mp.invoke(Object obj, Object[] args)调用其他同类对象的原方法或者mp.invokeSuper(Object obj, Object[] args)调用原始(父类)方法。


3.org.aopalliance的拦截体系


该包是AOP组织下的公用包,用于AOP中方法增强和调用。相当于一个jsr标准,只有接口和异常。在AspectJ、Spring等AOP框架中使用。


对应的方法拦截器org.aopalliance.intercept.MethodInterceptor:


public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation inv) throws Throwable;
}


调用时使用inv.proceed()调用原始方法。


附aopalliance包介绍:


详细介绍:


  1. Advice

    增强器标记接口

  2. Interceptor

    拦截器,Advice的子接口,标记拦截器。拦截器是增强器的一种。

  3. MethodInterceptor

    方法拦截器,Interceptor的子接口,拦截方法并处理。

  4. ConstructorInterceptor

    构造器拦截器,Interceptor的子接口,拦截构造器并处理。

  5. Joinpoint

    连接点。在拦截器中使用,封装了原方法调用的相关信息,如参数、原对象信息,以及直接调用原方法的proceed方法。

  6. Invocation

    Joinpoint的子类,添加了获取调用参数方法。

  7. MethodInvocation

    Invocation的子类,包含了获取调用方法的方法。

  8. ConstructorInvocation

    Invocation的子类,包含了获取构造器的方法。


Spring AOP框架的整合


先看一下通过Spring生成代理对象的代码:


// 生成基于实例的代理
public Object createProxy(Object bean, Advice advice) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(bean);
proxyFactory.addAdvice(advice);
return proxyFactory.getProxy();
}
// 生成基于接口的代理
public T createProxy(Class<T> interface, Interceptor interceptor) {
T proxy = new ProxyFactory(interface, interceptor).getProxy();
// 或者ProxyFactory.getProxy(interface, interceptor).getProxy();
return proxy;
}


针对上面的代码,结合源码进行分析,得到整个代理对象的创建过程。


准备:过程中出现的对象


  • AopProxyFactory接口

    AopProxy代理工厂类,用于生成代理对象AopProxy。


public interface AopProxyFactory {
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}


  • AopProxy

    代表一个AopProxy代理对象,可以通过这个对象构造代理对象实例。


public interface AopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader);
}


  • Advised接口

    代表被Advice增强的对象,包括添加advisor的方法、添加advice等的方法。

  • ProxyConfig类

    一个代理对象的配置信息,包括代理的各种属性,如基于接口还是基于类构造代理。

  • AdvisedSupport类

    对Advised的构建提供支持,Advised的实现类以及ProxyConfig的子类。

  • ProxyCreatorSupport类

    AdvisedSupport的子类,创建代理对象的支持类,内部包含AopProxyFactory工厂成员,可直接使用工厂成员创建Proxy。

  • ProxyFactory类

    ProxyCreatorSupport的子类,用于生成代理对象实例的工厂类,生成代码参考下面。

  • Advisor接口

    代表一个增强器提供者的对象,内部包含getAdvice方法获取增强器。

  • AdvisorChainFactory接口

    获取增强器链的工厂接口。提供方法返回所有增强器,以数组返回。

  • Pointcut接口

    切入点,用于匹配类与方法,满足切入点的条件是才插入advice。相关接口:ClassFilter、MethodMatcher。


分析:结合源码分析创建过程


以上准备做完之后,就可以看源码了,从获取代理对象的实例入口ProxyFactory.getProxy()开始:


public Object getProxy() {
// 创建AopProxy对象再获取代理对象实例
return createAopProxy().getProxy();
}
// createAopProxy方法在父类ProxyCreatorSupport中
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 先获取AopProxy的工厂对象,再把自己作为createAopProxy的参数AdvisedSupport传进去,用自己作为代理对象的配置
return getAopProxyFactory().createAopProxy(this);
}


代理对象实例最终是使用AopProxy.getProxy()得到的,他的调用是在AopProxyFactory.createAopProxy(AdvisedSupport config,createAopProxy有两个结果。一个是基于接口的JDK动态代理JdkDynamicAopProxy,一个是基于CGLib的生成类代理ObjenesisCglibAopProxy。源码如下:


public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

@Override
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() || Proxy.isProxyClass(targetClass)) {
// 如果目标类是接口,或者已经是Jdk的动态代理类,则创建jdk动态代理
return new JdkDynamicAopProxy(config);
}
// 否则创建Cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 如果声明创建Jdk动态代理则返回Jdk动态代理
return new JdkDynamicAopProxy(config);
}
}
}


传入的AdvisedSupport config中包含了需要注册的Method拦截器,AopProxy会保存这个config为advised对象。


基于JDK的动态代理


JdkDynamicAopProxy中getProxy会返回:


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, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 返回代理对象的实例
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}


自己作为InvocationHandler注册,看他的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.
// 没有声明equals方法,调用equals方法时,委托调用。
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
// 没有声明hashCode方法,调用hashCode方法时,委托调用。
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
// 如果调用的方法是DecoratingProxy中的方法,因为其中只有一个getDecoratedClass方法,这里直接返回被装饰的Class即可
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 代理不是不透明的,且是接口中声明的方法,且是Advised或其父接口的方法,则直接调用构造时传入的advised对象的相应方法
// 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.
// 如果暴露代理,则用AopContext保存当前代理对象。用于多级代理时获取当前的代理对象,一个有效应用是同类中调用方法,代理拦截器会无效。可以使用AopContext.currentProxy()获得代理对象并调用。
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
// 这里是关键,获得拦截链chain,是通过advised对象,即config对象获得的。
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 否则创建一个MethodInvocation对象,用于链式调用拦截器链chain中的拦截器。
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 != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 处理返回值
// 如果返回结果是this,即原始对象,且方法所在类没有标记为RawTargetAccess(不是RawTargetAccess的实现类或者子接口),则返回代理对象。
// 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);
}
}
}


注册的Method拦截器都是通过AdvisedSupport这个config对象的addAdvice或者addAdvisor注册进去的。


public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
// 如果是引介,则加入引介advisor。(新增功能)
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
else if (advice instanceof DynamicIntroductionAdvice) {
// We need an IntroductionAdvisor for this kind of introduction.
// jdk动态代理不支持动态引介
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
// 把advice转换为advisor并添加,目标是DefaultPointcutAdvisor。
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
}


其实也是把advice转成了advisor注册的。 看下最上面invoke方法中有一个方法调用:


List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);



public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 其实是通过advisorChainFactory工厂对象获得的
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}


是通过AdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法获取的,也把config对象传入了,且加的有缓存。其实是通过method获取该method对应的advisor。下面是他的唯一实现:


public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {

// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
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;
}

/**
* Determine whether the Advisors contain matching introductions.
*/

private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
for (int i = 0; i < config.getAdvisors().length; i++) {
Advisor advisor = config.getAdvisors()[i];
if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (ia.getClassFilter().matches(actualClass)) {
return true;
}
}
}
return false;
}

}


上面包括了各种对Advisor包装,通过Pointcut等的判断把Advisor中的Advice包装成MethodInterceptor、InterceptorAndDynamicMethodMatcher或者Interceptor。


之后在调用方法前,又把chain转换为了aopalliance体系的的MethodInvocation。


invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);


最终执行的是retVal = invocation.proceed()。 在ReflectiveMethodInvocation的proceed方法中,有整个拦截器链的责任链模式的执行过程,可以仔细看看,通过责任链序号方式执行的。


public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 链全部执行完,再次调用proceed时,返回原始对象方法调用执行结果。递归的终止。
return invokeJoinpoint();
}

Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 用currentInterceptorIndex记录当前的interceptor位置,初值-1,先++再获取。当再拦截器中调用invocation.proceed()时,递归进入此方法,索引向下移位,获取下一个拦截器。
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 如果是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 {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 如果是interceptor,则直接调用invoke。把自己作为invocation,以便在invoke方法中,调用invocation.proceed()来执行递归。或者invoke中也可以不执行invocation.proceed(),强制结束递归,返回指定对象作为结果。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}


基于Cglib的动态代理


看另外一种情况,Cglib的代理类:


ObjenesisCglibAopProxy继承自CglibAopProxy,整体对外暴露的接口和方法是与上面一致的,只有其真实实现换成了Cglib而已。


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, classLoader);

// Configure CGLIB Enhancer...
// 使用cglib库的enhancer,配置之后生成代理对象实例
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);
// 设置类生成策略,直接生成类的字节码byte[],可以深入研究
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

// 获取所有的callback,此时callback是cglib 的,getCallbacks中会把advisors封装成callback传入
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
// 生成callback类型数组
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
// 加入是否需要进行callback的过滤器,根据filter的返回的int值,cglib会执行不同的callback,索引分别对应上面的callback数组的索引:
// 0:AOP_PROXY、1:INVOKE_TARGET、2:NO_OVERRIDE、3:DISPATCH_TARGET、4:DISPATCH_ADVISED、5:INVOKE_EQUALS、6:INVOKE_HASHCODE
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);

// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
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 (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
// 不拦截构造方法
enhancer.setInterceptDuringConstruction(false);
// 设置拦截器callback
enhancer.setCallbacks(callbacks);
// 创建代理对象实例
return (this.constructorArgs != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}


直接看方法拦截器部分。注册拦截器是在getProxy方法中,注册进去的是cglib中的callback:


Callback[] callbacks = getCallbacks(rootClass)
enhancer.setCallbacks(callbacks);

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();

// Choose an "aop" interceptor (used for AOP calls).
// 生成aopInterceptor,用于AOP调用,这是调用拦截器链的核心,详看后面。
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;
// 下面根据不同情况,返回不同的Callback。
// targetSource的isStatic为true表示targetSource中的target是静态的不改变的,故直接缓存target即可。
// 为false则代表是动态的target,每次都需要getTarget来获取,这两种返回不同的callback,以便后续执行时使用不同情况的target。
// 而exposeProxy代表是否暴露代理对象到AopProxyContext中。
// 为true代表暴露,false不暴露。都需要返回不同的callback。
// 故总共有四种callback,且四种callback都有一个processReturnType的过程,同JdkDynamicAopProxy中的处理返回值。前面的操作也与JdkDynamicAopProxy中开始的目的相同。
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).
// 直接调用target的callback
Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
// callbackFilter返回的是callback的索引,用于调用这里的索引值对应的callback。
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
// 经过callbackFilter后,不需要被advice的对象,直接调用这个interceptor,性能最高。
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher,
// 调用advised中方法时,直接分配到advised中。
this.advisedDispatcher,
// equals方法
new EqualsInterceptor(this.advised),
// hashCode方法
new HashCodeInterceptor(this.advised)
};

Callback[] callbacks;

// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
// 这是一个优化,如果target是个不可变的静态对象,且advice链是固定不变的,则进行优化。内容见后面。
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

// TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
// 遍历所有方法,返回每个方法的拦截器链,并为每个方法生成一个包含拦截器链的callback。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
// 注意,这个fixedInterceptorMap还与callbackFilter关联,以便达到filter的目的。
// 同时保存索引到map中,以用于callbackFilter中返回索引。
this.fixedInterceptorMap.put(methods[x].toString(), x);
}

// Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
// 聚合所有callback
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
// 标记fixedInterceptor的偏移量,也会传入filter。
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}


上面提到callbackFilter的作用是返回需要调用的callback的序号,与上面的getCallbacks有比较大的关联,源码如下


// aopInterceptor: DynamicAdvisedInterceptor
private static final int AOP_PROXY = 0;
// targetInterceptor: 没有advise的方法
private static final int INVOKE_TARGET = 1;
// noOp: SerializableNoOp
private static final int NO_OVERRIDE = 2;
// targetDispatcher: isStatic ? StaticDispatcher : SerializableNoOp
private static final int DISPATCH_TARGET = 3;
// advisedDispatcher: AdvisedDispatcher
private static final int DISPATCH_ADVISED = 4;
// EqualsInterceptor
private static final int INVOKE_EQUALS = 5;
// HashCodeInterceptor
private static final int INVOKE_HASHCODE = 6;
// 其他索引直接通过fixedInterceptorMap获得
// 下面逻辑基本对应JdkDynamicAopProxy中判断逻辑
public int accept(Method method) {
if (AopUtils.isFinalizeMethod(method)) {
// 如果是final的方法,则返回NO_OVERRIDE
logger.debug("Found finalize() method - using NO_OVERRIDE");
return NO_OVERRIDE;
}
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Method is declared on Advised interface: " + method);
}
// advised上的方法,直接调用advised对象的对应方法
return DISPATCH_ADVISED;
}
// We must always proxy equals, to direct calls to this.
if (AopUtils.isEqualsMethod(method)) {
// 返回调用equals
logger.debug("Found 'equals' method: " + method);
return INVOKE_EQUALS;
}
// We must always calculate hashCode based on the proxy.
if (AopUtils.isHashCodeMethod(method)) {
// 返回调用hashCode
logger.debug("Found 'hashCode' method: " + method);
return INVOKE_HASHCODE;
}
Class<?> targetClass = this.advised.getTargetClass();
// Proxy is not yet available, but that shouldn't matter.
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 判断是否有拦截器链
boolean haveAdvice = !chain.isEmpty();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
if (haveAdvice || !isFrozen) {
// 如果有advice或者不是冻结的(不可改变的)
// If exposing the proxy, then AOP_PROXY must be used.
if (exposeProxy) {
if (logger.isDebugEnabled()) {
logger.debug("Must expose proxy on advised method: " + method);
}
// 如果需要暴露Proxy则返回aop代理
return AOP_PROXY;
}
String key = method.toString();
// Check to see if we have fixed interceptor to serve this method.
// Else use the AOP_PROXY.
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
// 通过fixedInterceptorMap获得对应索引,返回callback。
if (logger.isDebugEnabled()) {
logger.debug("Method has advice and optimizations are enabled: " + method);
}
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Unable to apply any optimizations to advised method: " + method);
}
return AOP_PROXY;
}
}
else {
// See if the return type of the method is outside the class hierarchy of the target type.
// If so we know it never needs to have return type massage and can use a dispatcher.
// If the proxy is being exposed, then must use the interceptor the correct one is already
// configured. If the target is not static, then we cannot use a dispatcher because the
// target needs to be explicitly released after the invocation.
if (exposeProxy || !isStatic) {
// 如果需要暴露,则要使用targetInterceptor
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
if (returnType.isAssignableFrom(targetClass)) {
// 如果返回类型是被代理类型的父类或者接口,有可能是返回this引用,需要用INVOKE_TARGET对返回值做处理
if (logger.isDebugEnabled()) {
logger.debug("Method return type is assignable from target type and " +
"may therefore return 'this' - using INVOKE_TARGET: " + method);
}
return INVOKE_TARGET;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Method return type ensures 'this' cannot be returned - " +
"using DISPATCH_TARGET: " + method);
}
// 不需要拦截,直接返回目标调用
return DISPATCH_TARGET;
}
}
}


这里的核心是把advised对象转成了Callback,注册到Enhancer中,那么拦截器链的执行应该是在


Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);


// 下面这段代码在我们调试Spring的时候回经常进来,特别是进入一个Bean的方法后再返回上一级调用时,最常见的就是这里。
// 这段代码基本与JdkDynamicAopProxy的invoke方法一致
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.
// 如果链是空且是public方法,则直接调用
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 否则创建一个CglibMethodInvocation以便驱动拦截器链
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// 处理返回值,同JDK动态代理
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}


这个和上面的jdk动态代理的invoke就比较像了,一样有List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);


最终的执行则是:


retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();


一样是转换为了aopalliance的invocation。注意CglibMethodInvocation是ReflectiveMethodInvocation的子类。区别在于CglibMethodInvocation内维护了cglib的MethodProxy,调用链执行完进行最终真实调用时,是调用了methodProxy.invoke(this.target, this.arguments)。


protected Object invokeJoinpoint() throws Throwable {
if (this.publicMethod) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return super.invokeJoinpoint();
}
}


其父类ReflectiveMethodInvocation的该方法是:


protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}


到这里基本问题都已经解决,还差最后一个优化点没有说,上面的FixedChainStaticTargetInterceptor与DynamicAdvisedInterceptor的区别在哪?代码如下,一看便知


public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 直接生成了CglibMethodInvocation,因为adviceChain是固定不变的,故在创建时已经传入,不需要每次执行时动态再计算了。
// 省略了暴露代理判断,无需进行context设置
MethodInvocation invocation = new CglibMethodInvocation(proxy, this.target, method, args,
this.targetClass, this.adviceChain, methodProxy);
// If we get here, we need to create a MethodInvocation.
Object retVal = invocation.proceed();
retVal = processReturnType(proxy, this.target, method, retVal);
return retVal;
}


致此结束,后面进行总结。


总结


再回顾一下上面的config对象,config为AdvisedSupport对象,其实整体是个代理配置对象


public class ProxyConfig implements Serializable
- public class AdvisedSupport extends ProxyConfig implements Advised
-- public class ProxyCreatorSupport extends AdvisedSupport
--- public class ProxyFactory extends ProxyCreatorSupport


最下层的ProxyFactory包含了特殊的功能,只能创建proxy对象,他是通过AopProxyFactory来做的:


public Object getProxy() {
return createAopProxy().getProxy();
}


createAopProxy()方法是ProxyCreatorSupport类支持的:


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

public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}

public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}


这样,ProxyFactory(AdvisedSupport config)就和AopProxyFactory有了联系,AopProxyFactory和AopProxy也有了联系,AopProxy和Proxy也有了联系。


结论


那么最终的结论是,Spring使用了Jdk动态代理和Cglib做代理,但是会把两种代理的拦截器转换为aopalliance这种标准形式进行处理。但是在公开给外部时,其实使用的是advisor这种形式,都注册为advisor或者advised即可。这样就统一了入口。


AspectJ框架也使用了aopalliance这种标准形式进行AOP代理,Spring对AspectJ在上层也有包装,可以研究一下。


相关研究


  1. Spring与aopalliance标准相关的类图 SpringAopAlliance

    Advice实现类中有一些adaptor,以及org.springframework.aop.framework.adapter包下一些其他适配器,他们的作用是把advice包装为advisor,把advice包装为MethodInterceptor。

  2. Spring其他声明代理对象Bean的方法

    1.BeanNameAutoProxyCreator


// org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator()
{
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("test");
beanNameAutoProxyCreator.setInterceptorNames("testInterceptor");
return beanNameAutoProxyCreator;
}


基本原理是使用BeanNameAutoProxyCreator自动对特定的Bean转换为特定拦截包装后的代理Bean,依然是使用了BeanPostProcessor,相关类参考下面。


public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor


ii. 使用@Aspect自动织入拦截器


@Component
@Aspect
public class LogAspect {

@Pointcut("execution(* com.demo.service..*.*(..))" )
public void inServiceLayer() { }

@Before(value = "execution(public * com.demo.service..*.*(..))" )
public void beforeShow() {
System.out.println("before show." );
}

@After(value = "execution(public * com.demo.service..*.*(..))" )
public void afterShow() {
System.out.println("after show." );
}

@Around("inServiceLayer()")
public Object around(ProceedingJoinPoint thisJoinPoint) throws Throwable {
return thisJoinPoint.proceed();
}

}


详细原理参考3


Spring中@Aspect注解声明的各种接入点是如何代理到Bean里面的,以及@Pointcut、@Before、@After、@AfterReturning、@AfterThrowing、@Around被包装为了什么。


4. 其他各种注解如何影响对象,如@Async、@Transactional(参考5)等。


基本原理是在@Async等的bpp(BeanPostProcessor,详细作用参考后续文章)的处理阶段中,检查目标bean是否被标记Advised接口,如果是则直接添加自己声明的实现特定功能的advisor,否则则使用ProxyFactory生成代理并添加自己的advisor。最终返回代理对象实例。


5.Transaction 在 Controller 层的探索


补充案例


Spring中一个动态代理实例,一个类中的一个方法,直接调用本类的@Async方法不触发代理,而@Configuration注解配置类却可以进行代理。为什么?


@Component
public class AsyncService {

AsyncService asyncService;

public void setCurrent(AsyncService asyncService) {
this.asyncService = asyncService;
}

public void async1() {
System.out.println("1:" + Thread.currentThread().getName());
// 通过代理对象调用
asyncService.async3();
// 通过this调用,不通过代理。因为this不是代理对象,而是真实对象。
this.async3();
// 即使创建了代理,最后一层的调用仍然是调用原始对象的对应方法,而不是使用代理对象的super.method()来进行调用的。
}


public void async2() {
System.out.println("2:" + Thread.currentThread().getName());
async3();
}

@Async
public void async3()
{
System.out.println("3:" + Thread.currentThread().getName());
}
}


当基于接口进行代理时,又是怎样的一种情况?


欲知详情,可参考本人下一篇文章


小技巧


1.如何导出被cglib代理的类:


Spring调用Enhance生成类时,最终总会生成类的字节码,在生成的地方导出即可,调试下发现是在这里:


org.springframework.cglib.core.DefaultGeneratorStrategy.generate(ClassGenerator cg)方法。


cglib生成类时,callbackFilter是生成时已经确定的,而不是动态调用filter来获得要调用的callback。即类生成时,每个方法要调用的callback已经自动织入到被代理方法的调用中了。在callbackFilter的accept方法中打断点,就能看到整个类的生成过程了。找到生成类的字节码也是在这里打断点找到的。


导出类文件:


File file = new File("E:\\Test.class");
// 建立输出字节流
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 用FileOutputStream 的write方法写入字节数组
try {
fos.write(b);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("写入成功");
// 为了节省IO流的开销,需要关闭
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


也可使用javaagent来导出,见后面。


扩展知识


Advice:增强,在目标方法范围内织入


Introduction: 引介,直接在类级别上添加目标未实现的接口方法


上面提到的动态代理有两种:


  1. Jdk动态代理

    Jdk自带的动态代理,使用Sun内部实现动态生成类,限制是只能对接口进行动态代理。

  2. CGLIB动态字节码生成

    动态生成现有类的子类并加载,可代理非接口。缺点是对于final声明的类以及private的方法无法进行代理。


除了上述两种方法外,还有以下三种代理方式


  1. 自定义类加载器

    通过自定义的类加载器,在类加载前对原类字节码进行替换,返回加入动态代理后的类的字节码加载到内存中。这种方式可代理任意类、接口。包括private方法和final类。但是当项目中使用了一些其他类加载器时,会导致使用其他类加载器的类代理无效化。参考FakeClassloader。

  2. 使用java agent进行字节码转换

    使用java.lang.Instrumentation接口提供的方法,在java agent的方法中进行动态字节码转换。

    对于预先加载的agent,可使用premain在main方法执行前进行类替换。对于动态attach的java agent,可在agentmain方法中动态替换当前内存中的类。

    对于预先加载的agent来说,这种方式几乎是万能的,除了需要额外加入启动参数外,几乎没有缺点。而对于动态attach的,则略微有些限制,只能替换方法中的实现,而不能修改方法签名。

  3. 静态AOP

    例如AspectJ框架,就是个静态代理的框架,在编译期直接编译进入字节码。对系统性能几乎无损耗,但是灵活度略微有些欠缺。


推荐阅读

(点击标题可跳转阅读)

Spring AOP是什么?你都拿它做什么?

Spring AOP 的实现机制

求求你,下次面试别再问我什么是 Spring AOP 和代理了!


看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能

好文章,我在看❤️

登录查看更多
0

相关内容

【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
【干货书】现代数据平台架构,636页pdf
专知会员服务
253+阅读 · 2020年6月15日
【新书】Java企业微服务,Enterprise Java Microservices,272页pdf
【新书】Python数据科学食谱(Python Data Science Cookbook)
专知会员服务
114+阅读 · 2020年1月1日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
微信小程序支持webP的WebAssembly方案
前端之巅
19+阅读 · 2019年8月14日
工行基于MySQL构建分布式架构的转型之路
炼数成金订阅号
15+阅读 · 2019年5月16日
Pupy – 全平台远程控制工具
黑白之道
43+阅读 · 2019年4月26日
Github项目推荐 | pikepdf - Python的PDF读写库
AI研习社
9+阅读 · 2019年3月29日
一天精通无人中级篇:遥控器协议 S-BUS
无人机
51+阅读 · 2018年12月20日
WebAssembly在QQ邮箱中的一次实践
IMWeb前端社区
13+阅读 · 2018年12月19日
最大熵原理(一)
深度学习探索
12+阅读 · 2017年8月3日
Arxiv
4+阅读 · 2019年8月7日
Nocaps: novel object captioning at scale
Arxiv
6+阅读 · 2018年12月20日
Arxiv
5+阅读 · 2018年12月18日
Arxiv
8+阅读 · 2018年5月15日
Arxiv
3+阅读 · 2018年4月9日
VIP会员
相关VIP内容
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
【干货书】现代数据平台架构,636页pdf
专知会员服务
253+阅读 · 2020年6月15日
【新书】Java企业微服务,Enterprise Java Microservices,272页pdf
【新书】Python数据科学食谱(Python Data Science Cookbook)
专知会员服务
114+阅读 · 2020年1月1日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
相关资讯
微信小程序支持webP的WebAssembly方案
前端之巅
19+阅读 · 2019年8月14日
工行基于MySQL构建分布式架构的转型之路
炼数成金订阅号
15+阅读 · 2019年5月16日
Pupy – 全平台远程控制工具
黑白之道
43+阅读 · 2019年4月26日
Github项目推荐 | pikepdf - Python的PDF读写库
AI研习社
9+阅读 · 2019年3月29日
一天精通无人中级篇:遥控器协议 S-BUS
无人机
51+阅读 · 2018年12月20日
WebAssembly在QQ邮箱中的一次实践
IMWeb前端社区
13+阅读 · 2018年12月19日
最大熵原理(一)
深度学习探索
12+阅读 · 2017年8月3日
Top
微信扫码咨询专知VIP会员