Spring笔记:AOP介绍与源码剖析

文章目录


前言

好记性不如烂笔头,做记录亦是复习。加油


一、AOP介绍

AOP本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、日志代码、事务控制代码、性能监控代码。
Spring笔记:AOP介绍与源码剖析
上图描述的就是未采用AOP思想设计的程序,当红色框中圈定的方法时,会带来大量的重复劳动。
程序中充斥着大量的重复代码,使程序的独立性很差。而下图中是采用了AOP思想设计的程序,它把红框部分的代码抽取出来的同时,运用动态代理技术,在运行期对需要使用的业务逻辑方法进行增强。
Spring笔记:AOP介绍与源码剖析
Spring 实现AOP思想使用的是动态代理技术,默认情况下Spring会根据被代理对象是否实现接口来选择使用JDK还是CGLIB。当被代理对象没有实现任何接口时,Spring会选择CGLIB。当被代理对象实现了接口,Spring会选择JDK官方的代理技术,不过可以通过配置的方式,让Spring强制使用CGLIB。


二、AOP源码剖析

好处: 提高培养代码架构思维、深入理解框架
原则:
定焦原则:抓主线
宏观原则:站在上帝视角,关注源码结构和业务流程(淡化具体某行代码的编写细节)读源码的方法和技巧
断点(观察调用栈)
反调(Find Usages)
经验(spring框架中doXXX,做具体处理的地方)

Spring源码构建步骤:
1.从github下载源码
2.安装gradle 5.6.3(类似于maven) Idea 2019.1 Jdk 11.0.5
3.导入(耗费⼀定时间)
4.编译工程(顺序:core-oxm-context-beans-aspects-aop)工程—>Tasks—>other—>compileTestJava
Spring笔记:AOP介绍与源码剖析

1.代理对象创建

1.1 AOP基础用例准备

Bean定义

	@Component
    public class LagouBean {
        public void tech() {
            System.out.println("java learning......");
        }
    }

Aspect定义

	@Component
    @Aspect
    public class LagouAspect {
        @Pointcut("execution(* com.lagou.*.*(..))")
        public void pointcut() {
        }

        @Before("pointcut()")
        public void before() {
            System.out.println("before method ......");
        }
    }

测试用例

	/**
     * 测试⽤例:Aop 代理对象创建
     */
    @Test
    public void testAopProxyBuild() {
        ApplicationContext applicationContext = new
                AnnotationConfigApplicationContext(SpringConfig.class);
        LagouBean lagouBean = applicationContext.getBean(LagouBean.class);
        lagouBean.tech();
    }

1.2 时机点分析

Spring笔记:AOP介绍与源码剖析
可以在 getBean 之前,LagouBean对象已经产生(即在第一行初始化代码中完成),而且该对象是一个代理对象(Cglib代理对象),所以可以断定,容器初始化过程中目标Bean已经完成了代理,返回了代理对象。

1.3 代理对象创建流程

AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object,
org.springframework.beans.factory.support.RootBeanDefinition)

	/**
     * 初始化Bean
     * 包括Bean后置处理器初始化
     * Bean的⼀些初始化⽅法的执⾏init-method
     * Bean的实现的声明周期相关接⼝的属性注⼊
     */
    protected Object initializeBean(final String beanName, final Object bean,
                                    @Nullable RootBeanDefinition mbd) {
        // 执⾏所有的AwareMethods
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        } else {
            invokeAwareMethods(beanName, bean);
        }
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 执⾏所有的BeanPostProcessor#postProcessBeforeInitialization 初始化之前的处理器⽅法
                    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean,
                    beanName);
        }
        try {
            // 这⾥就开始执⾏afterPropertiesSet(实现了InitializingBean接⼝)⽅法和initMethod
            invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable ex) {
            throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 整个Bean初始化完成,执⾏后置处理器⽅法
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

	@Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        // 循环执⾏后置处理器
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

Spring笔记:AOP介绍与源码剖析
创建代理对象的后置处理器AbstractAutoProxyCreator#postProcessAfterInitialization

/**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     *
     * @see #getAdvicesAndAdvisorsForBean
     */
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String
            beanName) {
        if (bean != null) {
            // 检查下该类是否已经暴露过了(可能已经创建了,⽐如A依赖B时,创建A时候,就会先去创建B。
            // 当真正需要创建B时,就没必要再代理⼀次已经代理过的对象),避免重复创建
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

暂停(有事,这文章后两天再往下写,先把作业提交了)

上一篇:如何记忆 Spring Bean 的生命周期


下一篇:Spring源码分析之循环依赖及解决方案