前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring5.0源码深度解析之SpringBean的Aop通知调用链源码分析

Spring5.0源码深度解析之SpringBean的Aop通知调用链源码分析

作者头像
须臾之余
发布2019-08-02 12:26:18
7900
发布2019-08-02 12:26:18
举报
文章被收录于专栏:须臾之余须臾之余

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

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

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

1、配置@EnableAspectJAutoProxy 2、@Import(AspectJAutoProxyRegistrar.class)往IOC容器中注入SpringAOP切面类 3、registerAspectJAnnotationAutoProxyCreatorIfNecessary()注册切面类 4、AnnotationAwareAspectJAutoProxyCreator.class注册到IOC容器中,【AOP的入口】 5、postProcessAfterInitialization 6、wrapIfNecessary()判断该对象是否在AOP的扫包范围内 7、createAopProxy()判断被代理类是否实现了接口,如果有实现了接口的化,是采用JDK动态代理,否则情况下就使用CGLIB代理 8、使用JdkDynamicAopProxy()方法实现代理类 9、最终执行目标方法的时候,就会进入到JdkDynamicAopProxy 的invoke()方法 10、底层使用集合存放使用通知,然后再使用责任链设计模式循环的调用

如果调用了目标方法,则最终进入invoke方法

SpringBean的生命周期

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

纯手写SpringAop调用链思路

【0】环绕通知之前执行→【1】前置通知→目标方法→【2】后置通知→【3】环绕通知之后执行 责任链设计模式,底层通过递归算法+责任链 如何存放起来:使用集合存放这些通知,集合当中不存放我们的方法,只存放链,那么如何插入我们的目标方法?

纯手写SpringAop调用链

MethodInterceptor 接口

代码语言:javascript
复制
public interface MethodInterceptor {
    /**
     * 定义共同通知骨架
     */
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException;
}

BeforMethodInterceptor 前置通知

代码语言:javascript
复制
public class BeforMethodInterceptor implements MethodInterceptor {
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println(">>>>前置通知<<<<");
        // 执行我们的目标方法
        methodInvocation.process();// 递归调用
    }
}

AfterMethodInterceptor后置通知

代码语言:javascript
复制
public class AfterMethodInterceptor implements MethodInterceptor {
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        // 执行我们的前置通知
        methodInvocation.process();
        System.out.println(">>>后置通知<<<");
    }
}

AroundMethodInterceptor 环绕通知

代码语言:javascript
复制
public class AroundMethodInterceptor implements MethodInterceptor {
    public void invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException {
        System.out.println("环绕通知在目标方法之前执行..");
        methodInvocation.process();
        System.out.println("环绕通知在目标方法之后执行..");
    }
}

UserService

代码语言:javascript
复制
public class UserService {
    public void login(String userName, Integer age) {
        System.out.println("userName:" + userName + ",age:" + age);
    }
}

MethodInvocation 能够把链串起来

代码语言:javascript
复制
public interface MethodInvocation {
    //调用链形成
    public void process() throws InvocationTargetException, IllegalAccessException;

}

DefaultMethodInvacation 实现通知串起来

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

执行结果:

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

下面我们看下源码是如何实现的

源码分析SpringAop

入口:

代码语言:javascript
复制
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
代码语言:javascript
复制
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
代码语言:javascript
复制
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
代码语言:javascript
复制
if (isEagerInit) {
    this.getBean(beanName);
}
代码语言:javascript
复制
public Object getBean(String name) throws BeansException {
    return this.doGetBean(name, (Class)null, (Object[])null, false);
}
代码语言:javascript
复制
if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
代码语言:javascript
复制
return proxyFactory.getProxy(this.getProxyClassLoader());
代码语言:javascript
复制
public Object getProxy(@Nullable ClassLoader classLoader) {
    return this.createAopProxy().getProxy(classLoader);
}

执行目标方面会进入invoke()方法

代码语言:javascript
复制
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   ...
    try {
      ....
            } else {
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                retVal = invocation.proceed();
            }
      ....
}
代码语言:javascript
复制
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 {
            return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

这里就是那五个通知后面还有个TransactionInterceptor,后面会分析它

本文参考

蚂蚁课堂:http://www.mayikt.com/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 纯手写SpringAop调用链思路
  • 纯手写SpringAop调用链
  • 源码分析SpringAop
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档