spring cglib 代理 无法获取父类属性_深入理解Spring框架之AOP实现原理

本篇内容将为下一篇@Async注解实现原理做铺垫,转自开源中国:https://dwz.cn/O09CJ3h

Spring AOP动态代理支持的核心

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

对应的方法拦截器:

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

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

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

  1. 通过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)调用原始(父类)方法。

  1. 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包介绍:

整个包的结构95d2a4fa0416e891e9711241bd3a96c6.png

详细介绍:

  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 interface, Interceptor interceptor) {
T proxy = new ProxyFactory(interface, interceptor).getProxy();
// 或者ProxyFactory.getProxy(interface, interceptor).getProxy();
return proxy;
}

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

准备:过程中出现的对象
  1. AopProxyFactory接口

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

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

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

public interface AopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader);
}
  1. Advised接口

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

  2. ProxyConfig类

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

  3. AdvisedSupport类

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

  4. ProxyCreatorSupport类

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

  5. ProxyFactory类

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

  6. Advisor接口

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

  7. AdvisorChainFactory接口

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

  8. Pointcut接口

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

类图如下: fd501e11643236795c3fc4a1b6c3de50.png

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

以上准备做完之后,就可以看源码了,从获取代理对象的实例入口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 chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List 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 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 interceptorList = new ArrayList(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(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 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 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标准相关的类图 3c56bbe98721641165496ac0202d9fb3.png

    Advice实现类中有一些adaptor,以及org.springframework.aop.framework.adapter包下一些其他适配器,类图如下:

    ad6ac575172385eec2c1ac430ef4030e.png

    他们的作用是把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 AbstractAutoProxyCreatorpublic abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAwarepublic class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBeanpublic interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorpublic 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

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

    相关类的类图如下:

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

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

@Asyncpublic 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框架,就是个静态代理的框架,在编译期直接编译进入字节码。对系统性能几乎无损耗,但是灵活度略微有些欠缺。


觉得有收获,诚邀关注、点赞、转发

03e0fdfd1f492e971d562b55052fa338.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值