子类重写方法aop切不到_Spring5.0源码深度解析:SpringBean的Aop通知调用链源码分析,小白都能看懂...

点击上方“Java分享吧”,选择“设为星标”

优选有价值的技术文献,从我做起

源码分析篇章

SpringAOP原理探究

思考:springAOP底层运用了什么设计模式?

生成代理类:代理设计模式、底层五个通知形成调用链采用:责任链设计模式

下面我们回顾下SpringAop实现流程:

1、配置@EnableAspectJAutoProxy:开启AOP权限

2、@Import(AspectJAutoProxyRegistrar.class):往IOC容器中注入SpringAOP切面类

3、registerAspectJAnnotationAutoProxyCreatorIfNecessary():注册切面类

4、AnnotationAwareAspectJAutoProxyCreator.class:注册到IOC容器中,【AOP的入口】

5、AnnotationAwareAspectJAutoProxyCreator:祖宗是BeanPostProcessor接口,而实现BeanPostProcessor接口后,当Spring加载这个Bean会在实例化前调用其后置处理器实现增强

6、postProcessAfterInitialization:后置处理器【AOP实现核心逻辑】

####6.1、wrapIfNecessary()判断该对象是否在AOP的扫包范围内,真正创建代理类的地方

#########6.1.1、getAdvicesAndAdvisorsForBean创建代理对象包括获取增强方法和根据获取的增强进行代理

#########6.1.2、createAopProxy()判断被代理类是否实现了接口,如果有实现了接口的化,是采用JDK动态代理,否则情况下就使用CGLIB代理

####6.2、根据条件判断使用JdkDynamicAopProxy或者JdkDynamicAopProxy方法实现代理

####6.3、最终执行目标方法的时候,就会进入到JdkDynamicAopProxy 的invoke方法或者JdkDynamicAopProxy的intercept方法

####6.5、底层使用集合存放使用通知,然后再使用责任链设计模式循环的调用

创建代理

我们先来总结下JDK和CGLIB方式

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP

  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP

  • 如果目标对象没有实现接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理和CGLIB字节码生成的区别?

JDK动态代理只能对实现了接口的类生成代理,而不能针对类。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或者方法最好不要声明为final

获取代理

1.JDK代理使用示例

public interface UserService {  //目标方法public abstract void add();
}
public class UserServiceImpl implements UserService {/**
* dynamic.proxy.UserService#add()
*/public void add() {
System.out.println("add.......");
}
}
public class MyInvocationHandler implements InvocationHandler { //目标对象private Object target;/**
* 构造函数
* @param target:目标对象
*/public MyInvocationHandler(Object target) {super();this.target = target;
}/**
* 执行目标对象的方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-------------before-----------");
Object result = method.invoke(target, args);
System.out.println("-------------after------------");return result;
}public Object getProxy(){return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(),this);
}
}
public class ProxyTest {public static void main(String[] args) {//实例化目标对象
UserService userService = new UserServiceImpl();//实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService); //根据目标对象生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();//调用代理对象的方法
proxy.add();
}
}

输出结果:

8ba1c2e8b883531d2a0af2829efde1c2.png

JdkProxy使用示例源码分析

我们再次回顾下JDK代理方式,在整个创建过程中,对于InvocationHandler的创建是最为核心的,在自定义的InvocationHandler中需要重写三个函数

构造函数,将代理的对象传入

invoke方法,此方法中实现了AOP增强的所有逻辑

getProxy方法,此方法千篇一律,但是必不可少。

那么我们看看Spring中的JDK代理实现是不是也是这么做的呢?继续之前的跟踪,到达JdkDynamicAopProxy的getProxy方法。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;
} else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;
} else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//如果循环遍历找到需要代理的对象,则会进入到这里创建代理this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;
} else {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}
} else {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}
}
protected Object createProxy(Class> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}return proxyFactory.getProxy(this.getProxyClassLoader());
}

获取了五个通知:

269c70c6d1ef9a69e789d6bb9f2eea2c.png

public Object getProxy(@Nullable ClassLoader classLoader) {return this.createAopProxy().getProxy(classLoader);
}

b4cd68deffdd5899ba91f10e4c180c9f.png

public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

90efe400422752e0d4f428e84be78684.png

我们可以推断出,在JdkDynamicAopProxy中一定会有个invoke函数,并且JdkDynamicAopProxy会把AOP的核心逻辑写在里面。我们查看代码发现确实是有invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
Class var9;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {Boolean var19 = this.equals(args[0]);return var19;
}if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
Integer var18 = this.hashCode();return var18;
}if (method.getDeclaringClass() != DecoratingProxy.class) {
Object retVal;if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);return retVal;
} //有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class> targetClass = target != null ? target.getClass() : null; //获取当前方法的拦截器链 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  //如果没有发现任何拦截器那么直接调用切点方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
} else {//将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链接
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  //执行拦截器链
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;
} 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);
}
Object var13 = retVal;return var13;
....
}

上面函数中主要是 创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中是怎么实现前置增强和后置增强

public Object proceed() throws Throwable {if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return this.invokeJoinpoint();
} else { //获取下一个需要执行的拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {//动态匹配
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice; //匹配则执行拦截器,不匹配不执行拦截器return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
} else {//普通拦截,直接调用拦截器,将this作为参数传递以保证当前实例中调用链的执行return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
}
}
}

在proceed方法中,ReflectiveMethodInvocation中的主要职责是维护了链接调用的计数器,记录当前调用链接的位置,以便链可以有序的进行下去。

CGLIB使用示例源码分析

public class EnhancerDemo {public static void main(String[] args) {Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(EnhancerDemo.class);
enhancer.setCallback(new MethodInterceptorImpl());
EnhancerDemo demo = (EnhancerDemo) enhancer.create();
demo.test();
System.out.println(demo);
}private void test() {
System.out.println("EnhancerDemo #test()....");
}private static class MethodInterceptorImpl implements MethodInterceptor{@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("------before invoke----"+method);
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("-----after invoke------"+method);return result;
}
}
}

运行结果

1ea49384ff9d345c4f4a91d673e17b0d.png

生成的对象为:com.xiaoxu.cglib.EnhancerDemo$$EnhancerByCGLIB$$c9092bbe@78e03bb5的实例,这个类是运行时由CGLIB产生的。

我们看下Spring源码对CGLIB的实现:

f8094c3ae6a835b4c7b22cc13c00f5cd.png

public Object getProxy(@Nullable 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;
int x;if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class>[] additionalInterfaces = rootClass.getInterfaces();
Class[] var5 = additionalInterfaces;
int var6 = additionalInterfaces.length;for(x = 0; x < var6; ++x) {
Class> additionalInterface = var5[x];this.advised.addInterface(additionalInterface);
}
}   //验证classthis.validateClassIfNecessary(proxySuperClass, classLoader);    //创建及配置Enhancer
Enhancer enhancer = this.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);
enhancer.setStrategy(new CglibAopProxy.ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));   //设置拦截器
Callback[] callbacks = this.getCallbacks(rootClass);
Class>[] types = new Class[callbacks.length];for(x = 0; x < types.length; ++x) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);return this.createProxyClassAndInstance(enhancer, callbacks);
} catch (IllegalArgumentException | CodeGenerationException var9) {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", var9);
} catch (Throwable var10) {throw new AopConfigException("Unexpected AOP exception", var10);
}
}

这里最重要的是通过getCallbacks方法设置拦截器链

private Callback[] getCallbacks(Class> rootClass) throws Exception { //对属性expose-proxy处理boolean exposeProxy = this.advised.isExposeProxy();boolean isFrozen = this.advised.isFrozen();boolean isStatic = this.advised.getTargetSource().isStatic();//将拦截器封装在DynamicAdvisedInterceptor中 Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
Object targetInterceptor;if (exposeProxy) {
targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
} else {
targetInterceptor = isStatic ? new CglibAopProxy.StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}
Callback targetDispatcher = isStatic ? new CglibAopProxy.StaticDispatcher(this.advised.getTargetSource().getTarget()) : new CglibAopProxy.SerializableNoOp();
Callback[] mainCallbacks = new Callback[]{aopInterceptor, (Callback)targetInterceptor, new CglibAopProxy.SerializableNoOp(), (Callback)targetDispatcher, this.advisedDispatcher, new CglibAopProxy.EqualsInterceptor(this.advised), new CglibAopProxy.HashCodeInterceptor(this.advised)};
Callback[] callbacks;if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];this.fixedInterceptorMap = new HashMap(methods.length);for(int x = 0; x < methods.length; ++x) {
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new CglibAopProxy.FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(methods[x].toString(), x);
}   //将拦截器加入到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);this.fixedInterceptorOffset = mainCallbacks.length;
} else {
callbacks = mainCallbacks;
}return callbacks;
}

在getCallbacks中spring考虑了很多情况,但是对于我们来说,只需要理解最常用的就可以了,CGLIB中对于方法的拦截是通过将自定义的拦截器(实现MethodInterceptor接口)加入到Callback中

并在调用代理时直接激活拦截器中的intercept方法来实现。由此可推断,对于CGLIB方式实现的代理,其核心逻辑必然在DynamicAdvisedInterceptor中的intercept中。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Object target = null;
TargetSource targetSource = this.advised.getTargetSource();Object var16;try {if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class> targetClass = target != null ? target.getClass() : null;  //获取拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  //如果拦截器链为空则直接激活源原方法
retVal = methodProxy.invoke(target, argsToUse);
} else { //进入链
retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
}
retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
var16 = retVal;
} finally {if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}return var16;
}

上述的实现与JDK方式实现代理中的invoke方法大同小异,首先是构造链,然后封装此链进行串联调用,区别在于JDK中直接构造ReflectiveMethodInvocation,而在CGLIB中使用CglibMethodInvocation.

CglibMethodInvocation继承自ReflectiveMethodInvocation,但是process方法并没有重写。

SpringBean的AOP

主要靠的是后置处理器BeanPostProcessor:在Bean对象初始化前后做一些增强

AnnotationAwareAspectJAutoProxyCreator的祖宗是BeanPostProcessor

纯手写SpringAop调用链思路

【0】环绕通知之前执行→【1】前置通知→目标方法→【2】后置通知→【3】环绕通知之后执行

责任链设计模式,底层通过递归算法+责任链

如何存放起来:使用集合存放这些通知,集合当中不存放我们的方法,只存放链,那么如何插入我们的目标方法?

纯手写SpringAop调用链

6fde3947562776aac3def73dad95ed52.png

public interface MethodInterceptor {/**
* 定义共同通知骨架
*/public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException;
}
public class BeforMethodInterceptor implements MethodInterceptor {public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
System.out.println(">>>>前置通知<<<); // 执行我们的目标方法
methodInvocation.process();// 递归调用
}
}
public class AfterMethodInterceptor implements MethodInterceptor {public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException { // 执行我们的前置通知
methodInvocation.process();
System.out.println(">>>后置通知<<);
}
}
public class AroundMethodInterceptor implements MethodInterceptor {public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
System.out.println("环绕通知在目标方法之前执行..");
methodInvocation.process();
System.out.println("环绕通知在目标方法之后执行..");
}
}
public class UserService {public void login(String userName, Integer age) {
System.out.println("userName:" + userName + ",age:" + age);
}
}

MethodInvocation 能够把链串起来

public interface MethodInvocation {//调用链形成public void process() throws InvocationTargetException, IllegalAccessException;
}
public class DefaultMethodInvacation implements MethodInvocation {/**
* 存放所有的通知
*/private List listMethodInterceptor;private Object target;// 目标对象private Method method;// 目标方法private Object args[];// 目标参数 // 最终使用反射机制执行目标方法private int index;// 记录当前链调用的位置public DefaultMethodInvacation(List listMethodInterceptor, Object target, Method method, Object[] args) {this.listMethodInterceptor = listMethodInterceptor;this.target = target;this.method = method;this.args = args;
}/**
* 调用链形成
*/@Overridepublic void process() throws InvocationTargetException, IllegalAccessException {if (index == listMethodInterceptor.size()) {
method.invoke(target, args); // 执行目标return;
}
MethodInterceptor methodInterceptor = listMethodInterceptor.get(index++);
methodInterceptor.invoke(this);
}
}

执行结果:

7ea614303209a34ec7e1915b06d4afc9.png

>>>>前置通知<<<<
环绕通知在目标方法之前执行..
userName:mayikt,age:12
环绕通知在目标方法之后执行..
>>>后置通知<<<


历史技术文献

 
  • 多线程进阶,JUC并发编程之抽象同步队列AQS框架设计理念一探究竟

  • 今日实战案例:设计模式之外观模式(门面模式),并利用到接口设计当中

  • 谈谈我是如何在聚合支付平台,巧用模板+工厂设计模式来实现异步回调,看完就能明白

  • 京东Java高级工程师,浅谈代理设计模式,看完就能明白了~

  • 设计模式之策略模式实战案例,如何重构聚合支付平台,对接支付宝、微信、银联支付?

文章有帮助可以点个「在看」或「分享」,分享不易,请兄弟姐妹们点下吧!

我是吧主,Java干货分享,记录每一位程序员的点点滴滴故事,每篇文章原创与当下程序员,架构师,日常总结经验,全网唯一良心原创无广告平台~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值