Spring AOP 流程

proxy实例化
1. 根据是否有interface准备proxy:JdkDynamicAopProxy.getProxy()/CglibAopProxy.getProxy()

JDK:

	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就是JdkDynamicAopProxy本身


CGLIB:

	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		enhancer.setInterceptDuringConstruction(false);
		enhancer.setCallbacks(callbacks);
		return (this.constructorArgs != null ?
				enhancer.create(this.constructorArgTypes, this.constructorArgs) :
				enhancer.create());
	}

 其中Callback[] 是CglibAopProxy静态内部类,有多个


共通:最重要的属性是AdvisedSupport advised; 可以想象为PointcutAdvisor的仓库


proxy方法调用

2. CGLIB调用MethodInterceptor.intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)

    JDK调用InvocationHandler.invoke(Object proxy, Method method, Object[] args)

Step1: 得到当前method对应的advice调用链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Step2: 
chain.isEmpty()==true: 直接调用target的对应method
chain.isEmpty()==false: 调用advice的invoke(MethodInvocation invocation) 在方法中可以通过invocation.proceed();继续调用chain的对应的下一个advice直到target。


Note:

1.

Spring的AOP实现可能是对JDK动态代理的妥协,让CGLIB的callback模拟JDK的InvocationHandler持有当前的target。正是因为Spring实现中最终都是调用的target的method,因此Spring的proxy方法调用自己的其他方法时不会触发AOP。

2.

有个有意思的地方在被CGLIB动态代理过的类再被Spring的AOP代理一次就会变成用JDK代理,因为CGLIB动态代理默认会继承一些接口。

正因为如此,这里会有个尴尬的地方,如果一个bean本身没有用接口,但是又被会被代理两次以上(第一次CGLIB,第二次JDK),那用@Autoware的地方就会抛错类似于:

Bean named 'xxxxxxx' is expected to be of type 'xxxxxxxx' but was actually of type 'com.sun.proxy.$Proxy21'
这时候解决办法有两个:

一:给bean加个接口

二:强制使用CGLIB : proxyTargetClass="true"


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值