# small-spring **Repository Path**: kraslzk/small-spring ## Basic Information - **Project Name**: small-spring - **Description**: mini-spring - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-10-17 - **Last Updated**: 2024-02-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #Spring ##step-01 简单Bean容器 ①创建简单的bean容器 ②定义`BeanDefinition`对象,保存bean对象 ③在`beanFactory`定义bean的存储容器和存取方法 ④通过`beanFactory`获取bean对象进行方法调用 ##step-02 Bean的定义,注册,获取 ①`BeanDefinition` 由存储bean对象改为存储类信息,这是将实例化bean交给spring的第一步 ②`SingletonBeanRegistry` 获取单例对象的接口 ③`DefaultSingletonBeanRegistry` 继承`SingletonBeanRegistry` ,定义单实例bean的存储容器和存取方法 ④`BeanFactory` 获取bean对象的接口 ⑤`AbstractBeanFactory`,定义模板方法, 继承 `DefaultSingletonBeanRegistry` 可以注册,存取单例对象;继承`BeanFactory`,实现bean对象的获取方法, 定义getBeanDefinition,createBean等抽象方法,如果无法从单实例容器获取到bean对象时,调用两个方法创建bean实例。 ⑥`AbstractAutowireCapableBeanFactory` 继承`AbstractBeanFactory`,实现createBean方法,实例化bean。 ⑦`BeanDefinitionRegistry` 定义注册BeanDefinition的接口 ⑧`DefaultListableBeanFactory`(核心类)继承`AbstractAutowireCapableBeanFactory`,有了createBean的能力; 实现`BeanDefinitionRegistry`#registerBeanDefinition、`AbstractBeanFactory`#getBeanDefinition,使得拥有beanDefinitionMap 存取bean的能力;具有对BeanDefinition容器、单例容器的操作。 【调用流程】 ①实例化`DefaultListableBeanFactory` ②将UserService类作为构造器参数,实例化BeanDefinition对象, ③第①步的工厂对象调用registerBeanDefinition方法,将第②步的beanDefinition对象注册到BeanDefinitionMap容器 ①利用工厂获取UserService的bean对象,先从单例对象容器中获取,获取不到就从BeanDefinition容器中获取 UserService类并实例化(newInstance),并将实例化对象存入单例对象容器中,方便下次调用 ③第二次调用UserService的bean对象时,就可以直接从单例Bean对象容器中获取了 ![img.png](img.png) ##step-03 CGLib or JDK 代理实现bean的实例化 解决实例化bean时有参构造器问题 ①`BeanFactory` 中新增带参数getBean方法,具备获取有参bean的能力 ②`InstantiationStrategy` 实例化策略接口,提供实例化方法instantiate ③`SimpleInstantiationStrategy` 通过JDK代理,Class类#getDeclaredConstructor获取构造器,netInstance获取实例对象 ④`CGLibSubclassingInstantiationStrategy` 通过CGLib动态代理的Enhancer对象,获取Class类,实例化对象 ⑤`AbstractAutowireCapableBeanFactory` 新增createBeanInstance方法,通过反射获取Class#getDeclaredConstractors,当前类的所有构造器, 根据传进来的参数决定使用哪个构造器,再调用③或④中instantiate方法实例化对象。 ![img_1.png](img_1.png) ##step-04 注入属性和依赖对象 解决实例的属性赋值问题 ①`PropertyValue` 属性,包含属性名和值 ②`PropertyValues` 使用List存放的属性PropertyValue ③`AbstractAutowireCapableBeanFactory`#applyPropertyValues,在创建完实例对象之后,设置实例属性, 如果属性是基本类型,直接使用BeanUtil设置值;如果是引用类型,则需要递归处理,获取bean,再设置属性。 ![img_2.png](img_2.png) ##step-05 资源加载器解析xml文件实现bean注册 解决前面注册bean需要手动写代码注入问题,本章将使用xml文件注册bean ①`Resource` 接口,提供统一获取字节流的方法#getInputStream,并且提供三个实现类,分别从不同方式获取字节流 a `ClasspathResource` 使用 `ClassLoader` #getResourceAsStream获取字节流 b `FileSystemResource` 使用 `FileInputStream` 从文件系统获取字节流 c `UrlResource` url.openConnection.getInputStream 从网络资源获取字节流 ②`ResourceLoader` 接口,提供获取资源的方法getResource,默认实现类 `DefaultResourceLoader` 根据路径(a、b、c)从不同获取相应resource ③创建 `BeanDefinitionReader` 接口,提供获取BeanDefinition注册器和资源加载器的方法,以及三个不同方式加载资源的方法 ④抽象类 `AbstractBeanDefinitionReader` 实现了 `BeanDefinitionReader` 接口,内部持有BeanDefinition注册器和ResourceLoader资源加载器 ⑤`XmlBeanDefinitionReader` 继承抽象类 `AbstractBeanDefinitionReader` 实现解析xml文件,将xml文件配置的bean注册到容器。 ⑥`BeanFactory` 中新增getBean方法重载,获取指定类型的bean ⑦`ListableBeanFactory` 是一个扩展 `BeanFactory` 的接口,有新增的扩展方法 ⑧`HierarchicalBeanFactory` spring源码中提供了他可以获取父类BeanFactory方法,是扩展工厂的层次子接口 ⑨`AutowireCapableBeanFactory` 自动化处理Bean工厂配置的接口 ⑩`ConfigurableBeanFactory` 可获取 `BeanPostProcessor`,`BeanClassLoader` 等的一个配置接口 11 `ConfigurableListableBeanFactory` 提供分析,修改Bean以及预先实例化的操作接口 ![img_3.png](img_3.png) ##step-06 应用上下文管理 上一章实现了xml注册bean,本章构建应用上下文帮助管理 BeanFactory 和 对资源的加载解析,解决需要手动获取BeanFactory和创建资源加载器的问题 【实现过程:在继承链上,各个抽象类实现不同的功能,最后创建出一个拥有完整功能的实现类】 ①`ApplicationContext` 接口,继承 `ListableBeanFactory` 拥有获取bean的方法getBean ②`ConfigurableApplicationContext` 接口,继承 `ApplicationContext` 提供刷新容器的方法 ③`AbstractApplicationContext` 抽象类,继承 `DefaultResourceLoader` a.模板模式实现refresh方法 b.提供抽象方法刷新和获取beanFactory c.调用注册的 `BeanFactoryPostProcessor` 提前修改相关 `BeanDefinition` d.将bean初始化注册到beanFactory e.实现获取bean的方法getBean ④抽象类 `AbstractRefreshableApplicationContext` 继承 `AbstractApplicationContext` a.内部持有一个完全体BeanFactory引用 b. 创建beanFactory c.提供抽象方法加载BeanDefinition到注册器中 d.实现获取beanFactory的方法 ⑤抽象类 `AbstractXmlApplicationContext` 继承抽象类 `AbstractRefreshableApplicationContext` a.实通过资源加载器和解析器来将 `BeanDefinition` 加载到注册器中 b.提供抽象方法获取资源位置 ⑥ `ClassPathXmlApplicationContext` 继承抽象类 `AbstractXmlApplicationContext` a.负责缓存和获取资源位置 b.多层继承下来该类继承了所有功能 【Bean扩展接口】 1.创建 `BeanFactoryPostProcessor` 接口提供bean生成之前对相关bean的 `BeanDefinition` 进行修改操作 2.创建 `BeanPostProcessor` 接口提供bean初始化时前置和后置处理方法 【完成后只需要获取应用上下文即可对整个容器进行资源加载、解析、工厂注册bean】 【详细过程】 1.new `ClassPathXmlApplicationContext`("classpath:spring.xml");生成 `ClassPathXmlApplicationContext` 类, 该类将传入有参构造器的参数进行缓存,然后调用其顶级父类 `AbstractApplicationContext` 提供的refresh模板方法 2.refresh模板方法内规定了上下文对象构建的逻辑 ```java public void refresh() throws BeanException { // 1.创建beanFactory 加载BeanDefinition refreshBeanFactory(); // 2.获取BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 3.在bean实例化之前,执行BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // 4.BeanPostProcessor需要提前于其他Bean注册到容器 registerBeanPostProcessors(beanFactory); // 5.提前实例化Bean对象 beanFactory.preInstantiateSingletons(); } ``` a.首先进行创建完全体BeanFactory:`DefaultListableBeanFactory`,上下文对象要先持有bean工厂才能将加载资源 解析解析后生成的BeanDefinition存起来,此项任务交由 `AbstractRefreshableApplicationContext` 来完成 b.创建完工厂后需要将资源加载和解析生成的BeanDefinition缓存到工厂类中,此任务交由 `AbstractXmlApplicationContext` 完成,此时我们的工厂类中的BeanDefinition缓存池的内容为: i.定义的bean的BeanDefinition ii.实现 BeanFactoryPostProcessor 的BeanDefinition ii实现 BeanPostProcessor 的BeanDefinition c.实现 `BeanFactoryPostProcessor` 的类是对BeanDefinition直接操作,因此首先将该bean创建出来并执行 d.实现 `BeanPostProcessor` 的类是在bean创建时对bean进行操作,所以暂时将其存入 `AbstractBeanFactory` 持有的缓存中 e.然后实例化所有bean对象 i.根据生成策略生成基本bean对象 i. 进行属性注入 ii.对bean进行初始化,此时调用bean工厂中 BeanPostProcessor 缓存进行对bean处理 ![img_5.png](img_5.png) ##spring-step-07 bean的初始化和销毁工作 预留扩展接口供使用者对bean进行初始化和销毁工作 ① `InitializingBean` 接口,提供初始化方法afterPropertiesSet(),需要初始化的bean只需实现该接口,实现方法 ② `DisposableBean` 接口,提供销毁bean前的处理方法destroy(),bean只需实现该接口方法即可 ③ `DisposableBeanAdapter` 是 `DisposableBean` 的实现类,重写了destroy方法,规定destroy方法执行的先后顺序以及处理重复销毁的问题 【项目更新】 ① `BeanDefinition`:定义initMethodName、destroyMethodName,解析spring.xml中的init-method、destroy-method存至这两个属性 ② `XmlBeanDefinitionReader`:解析spring.xml,将init-method、destroy-method存入beanDefinition ③ `AbstractAutowireCapableBeanFactory`:获取实例化bean之后,执行Bean对象的初始化方法,初始化方法可以 是InitializingBean实现类中的初始化方法,也可以是spring.xml中init-method注册的方法 ④ `ConfigurableBeanFactory`:定义销毁单例容器disposableBeans的方法destroySingletons ⑤ `DefaultSingletonBeanRegistry`:实现destroySingletons,遍历移除disposableBeans容器中的元素 DisposableBean,每次移除后调用DisposableBean的destroy方法 ⑥ `ConfigurableApplicationContext`:定义registerShutdownHook、close方法 ⑦ `AbstractApplicationContext`:实现⑥定义的接口,即定义Runtime.getRuntime().addShutdownHook方法,该方法 会开启新线程,在JVM关闭前调用自定义的close方法,close方法会调用⑤中的销毁方法 【执行流程】 ①spring.xml的UserDao中定义init-method="initDataMethod'"、destroy-method:="destroyDataMethod" ②让UserService实现InitializingBean,、DisposableBean接口,则需要实现了初始化和销毁方法,①②相当于提供了两种初始化、销毁的方法 ③在资源解析时将init-method、destroy-method注入beanDefinition ④实例化Class类后,初始化Bean对象时,调用①、②中定义的初始化方法 ⑤定义ShutdownHook,在JVM销毁前执行自定义的线程,完成①、②中定义的销毁方法对bean初始化和销毁善后工作,提供两种方法: a:实现 `InitializingBean` 接口和 `DisposableBean` 接口,重写方法,bean初始化后直接调用接口方法; b:在spring.xml配置文件注册bean时配置 init-method="" 和 destroy-method="",通过反射调用; ![img_6.png](img_6.png) ##spring-step-08 Aware感知容器对象 ① `Aware`:标记类接口(类似标签),实现该接口可以被Spring容器感知 ② `BeanClassLoaderAware`:实现此接口,能感知到所属的ClassLoader ③ `BeanFactoryAware`:实现此类,能感知到所属的BeanFactory ④ `BeanNameAware`:实现此接口,能感知到所属的BeanName ⑤ `ApplicationContextAware`:实现此接口,能感知到所属的ApplicationContext ⑥ `ApplicationContextAwareProcessor`:继承BeanPostProcessor,那么在Bean初始化时就会调用该类中定义的 postProcessBeforeInitialization方法给Bean对象赋值applicationContext,实现感知ApplicationContext 【项目更新】 ⑦ `AbstractApplicationContext`:在refresh中调用beanFactory#addBeanPostProcessor(new ApplicationContextAwareProcessor(this),将⑥新增的类实例化至beanPostProcessors容器 ⑧ `AbstractAutowireCapableBeanFactory`:在initializeBean方法中执行invokeAware,即判断本次实例化的Bean实现哪些Aware的子接口,调用setXXX将将Spring内部对象注入Bean中 ⑨ `AbstractBeanFactory`:定义、实例化ClassLoader,并对外提供获取方法getBeanClassLoader ![img_7.png](img_7.png) ##spring-step-09 对象作用域scope和FactoryBean ①`BeanDefinition` 新增作用范围定义scope,并在 `XmlBeanDefinitionReader` 新增对xml文件中scope的解析,并填充到BeanDefinition的scope属性中。 ② `AbstractAutowireCapableBeanFactory` 的createBean()创建对象时,根据是否是单例和原型模式,判断是否存入内存中。 且在registerDisposableBeanIfNecessary注册销毁方法时,非单例Bean不需要注册且执行销毁方法。 非Singleton类型的Bean不执行销毁方法,单例Bean只会初始化一次,使用完成之后代表整个程序也就执行完毕。而其他类型则不一定。 ③ 定义 `FactoryBean` 接口 ④ 定义 `FactoryBeanRegistrySupport` 抽象类继承于 `DefaultSingletonBeanRegistry` ,提供对FactoryBean的一系列注册操作: getCachedObjectForFactoryBean获取缓存中的单例对象;getObjectFromFactoryBean获取对象的逻辑操作: 判断是否单例,若是单例则从缓存中获取,第一次获取则需存入缓存,若不是单例,则直接获取且不存入缓存。 ⑤ 扩展 `AbstractBeanFactory` 创建对象逻辑,将原本继承 `DefaultSingletonBeanRegistry` 修改为继承 `FactoryBeanRegistrySupport` , 即在原来的基础上插入一个逻辑块,这样即方便扩展也不影响原来的功能。新增getObjectForBeanInstance(beanInstance,beanName)方法, 判断是否属于FactoryBean以及调用getObjectFromFactoryBean方法,判断是否能获取FactoryBean缓存中的对象。 【FactoryBean】 在之前的设计中,Spring IoC容器通过反射或字节码增强的方式实例化Bean,但有些情况下,实例化较复杂,要往xml里填写大量的配置信息,且过程不能为用户支配。 就像我们之前的实现,要注册UserService,还要在xml配置内部的UserDao,万一以后又多了一个EventDao了呢?当需要往xml配置里塞的东西越来越多,本来简单的操作,也会变成庞大,难以理解的屎山。 FactoryBean很好的解决了这一点,它是一个对用户暴露的客制化Bean实例化的接口,用户可以通过实现该接口定制实例化Bean的逻辑。可以隐藏实例化一些复杂Bean的细节。 给上层应用带来便利。说人话就是,将一个待实例化的bean内部所有自定义类型都丢到FactoryBean代理。 FactoryBean是用于获取Bean,但和BeanFactory不太一样,BeanFactory获取的是静态的类,就比如我们写的Service的各个实现类,它的逻辑就是我拿到你的Bean定义,然后步步构造后作为Spring的Bean. FactoryBean不关心怎么构造出来这个Bean,对于他来讲,只要你实现了我的getObject方法,我就能拿到你这个Bean,这样他就更灵活,可以给一些第三方来用。 现实中的例子,Mybatis的Dao,我们使用Dao时,一般不是只需要写一个Dao的接口可以,这就是Mybatis通过FactoryBean实现了一个MapperFactoryBean可以获取到一个BaseMapper. 其中封装了可以从数据库获取数据的CURD等操作,这样我们写DAO只需要继承BaseMapper,MapperFactoryBean会帮我们把BaseMapper所有实现的DAO都注入,并在其中封装好查询操作,我们使用时啥都不需要关心。 也就是说,FactoryBean可以帮我们注入一类Bean,这类Bean所需要的通用依赖或者信息我们可以通过FactoryBean实现类统一处理,并注入。 ![img_8.png](img_8.png) ##spring-step-10 容器事件和事件监听器 ① 定义 `ApplicationEvent` 抽象类,继承于java.util.EventObject,从而具备事件功能,所有的事件类都需要继承该类。 ② 定义上下文中的事件类 `ApplicationContextEvent` ,继承于 ApplicationEvent ,并新增getApplicationContext方法获取事件来源的方法,容器中的事件以及用户自定义的事件都需继承该类。 ③ 定义容器刷新事件 `ContextRefreshedEvent` 以及容器关闭 `ContextClosedEvent` 事件类。 ④ 定义 `ApplicationListener` 事件监听器泛型接口,提供事件处理的方法。 ⑤ 定义 `ApplicationEventMulticaster` 事件处理器接口,提供添加、删除事件监听器以及发布事件的方法。 ⑥ 定义 `AbstractApplicationEventMulticaster` 抽象类,实现 `ApplicationEventMulticaster`、`BeanFactoryAware` 接口, 提取事件处理器中公用方法添加、删除事件监听器以及感知beanFactory的方法实现,并新增过滤监听器的方 法:主要是通过获取监听器接口的类型参数,并判断是否可以与event进行相互转换。 ⑦ 定义 `SimpleApplicationEventMulticaster` 类,继承于 `AbstractApplicationEventMulticaster` 抽象类,提供构造函数 感知BeanFactory,并实现 `ApplicationEventMulticaster` 事件处理器中发布事件的方法。 ⑧ 定义 `ApplicationEventPublisher` 事件发布者接口,提供事件的发布方法。 ⑨ 完善 `AbstractApplicationContext`,新增publishEvent(ApplicationEvent)发布事件方法,并在刷新容器refresh方法中新增注册事件发布者、 添加事件监听器以及发布容器刷新事件的动作,以及完善close方法,新增发布容器关闭事件的方法。 【事件过滤】 过滤监听器主要是判定此eventClassName对象所表示的类或接口与指定的event.getClass()参数所表示的类或接口是否相同,或是否是其父类或父接口。 首先获取不同实例化对象的Class,Cglib代理类需要获取父类Class,普通JDK的则不需要,在获取到Class之后通过**提取接口和对应的类型参数**以及eventClassName, 最后与入参中的event进行isAssignableFrom判断。 ```java protected boolean supportsEvent(ApplicationListener listener, ApplicationEvent event) { Class listenerClass = listener.getClass(); // 区分CGLib 和JDK代理的实例化类型 Class targetClass = ClassUtil.isCGLibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass; Type genericInterface = targetClass.getGenericInterfaces()[0]; Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0]; String className = actualTypeArgument.getTypeName(); Class eventClassName; try { eventClassName = Class.forName(className); } catch (ClassNotFoundException e) { throw new BeanException("wrong event class name : " + className); } return eventClassName.isAssignableFrom(event.getClass()); } ``` isAssignableFrom方法是从类继承的角度去判断,instanceof关键字是从实例继承的角度去判断。 isAssignableFrom方法是判断是否为某个类的父类,instanceof关键字是判断是否某个类的子类。 【观察者模式】 当一个行为发生时,传递信息给另一个用户,执行相应的处理行为,这两个行为之间没有耦合关系,而是通过监听实现。例如MQ的消息生成与消费、总线监听,都体现了观察者模式 ![img_9.png](img_9.png) ##spring-step-11 AOP切面实现 ① 定义 Pointcut 切点接口,springAOP对切点的顶层抽象,贯穿整个AOP; 在该接口中主要负责对系统的相应的 JoinPoint 进行捕捉,对系统中所有的对象进行 JoinPoint 所定义的规则进行匹配。 ClassFilter 与 MethodMatcher 分别用于在不同的级别上限定 JoinPoint 的匹配范围,满足不同粒度的匹配 ② 定义 MethodMatcher 方法匹配器,判断方法是否符合切点表达式 ③ 定义切点表达式 AspectJExpression ,与表达式 Expression 相关,依赖 AspectJ 的jar包解析表达式;在实现过程中,它充当 方法匹配器(MethodMatcher)、 类筛选器(ClassFilter)、还是切点(Pointcut),实现matches方法(类筛选和方法匹配)。 ④ 定义 AdvisedSupport 组装代理信息,AdvisedSupport { TargetSource 代理目标对象,MethodInterceptor 方法拦截器,MethodMatcher 方法匹配器} ⑤ 定义 TargetSource 代理目标对象,用于获取当前 MethodInvocation (方法调用)所需的 target (目标对象), target 通过反射方式被调用 method.invoke(target, args) ,proxy 代理的不是 target 而是 targetSource。 _为什么 Spring Aop 代理不直接代理 target,而是通过代理 TargetSource 间接代理 target? 在通常情况下,一个 proxy 只能代理一个 target,每次方法调用的目标也是唯一固定的 target。 但如果让 proxy 代理 TargetSource,可以使得每次方法调用的 target 实例不同,这种机制使得方法的调用变得灵活,可以扩展很多高级功能, 例如目标对象池(target pool),运行时目标对象热替换(hot swap)(当前并未实现这些扩展,非核心机制_) ⑥ 定义 MethodInterceptor 方法拦截器,可以对拦截方法做增强处理。 ⑦ 约定代理接口 AopProxy ,用于获取代理类,可以有JDK代理(JDKDynamicAopProxy)和CGLib代理(CGLibAopProxy)两种实现。 ⑧ MethodInvocation 方法执行器,在方法拦截器的增强方法中的形参,可以在执行器中获取目标方法代理调用 ⑨定义 ReflectiveMethodInvocation JDK代理方法执行器和 CGLibMethodInvocation CGLib代理方法执行器,因为两种代理实现有所不同。 在执行代理目标的方法之前,会进入代理对象的invoke方法,在该方法中判断目标方法是否符合切点表达式,如果符合,则获取拦截器,调用增强方法,在增强方法里会调用目标方法。 ![img_10.png](img_10.png) ##spring-step-12 AOP融入bean生命周期 【拦截器链】 ① `BeforeAdvice` :继承AOP联盟接口 `Advice`,定义前置通知接口,Spring的AOP把Advice细化了BeforeAdvice、AfterAdvice、.AfterReturningAdvice、ThrowsAdvice(即环绕拦截), 目前我们做的测试案例中只用到了BeforeAdvice,这部分可以对照Spring的源码进行补充测试。 ②`MethodBeforeAdvice` :继承 `BeforeAdvice` ,接口中定义before(Method method,Object[] args,Object targetObj)方法,由自定义的增强方法实现具体的增强逻辑(即前置通知方法) ③`UserServiceBeforeAdvice`:实现 `MethodBeforeAdvice` ,即完成自定义的增强逻辑 【访问者】 ①`Advisor`:定义访问者接口,接口中定义getAdvice方法,获取拦截器,Advice决定JoinPoint的执行操作 ②`PointcutAdvisor`:继承 Advisor ,该接口聚集Pointcut+Advisor的功能,Pointcut用于获取接入点JoinPoint, 而Advice决定JoinPoint的执行操作,定义获取接入点getPointcut方法 ③`AspectJExpressionPointcutAdvisor`:继承 `PointcutAdvisor`,实现了 `PointcutAdvisor` 接口,将切面 `AspectJExpressionPointcut`、拦截方法Advice和拦截表达式包装在一起,这样就可以在xml中定义一个pointcutAdvisor切面拦截器了 【方法拦截器】 ①`MethodBeforeAdviceInterceptor`:方法拦截器,跟上一的 `UserServiceInterceptor` 一样,invoke方法中包含了反 射调用增强方法和目标对象的方法,跟上一章不同的是,将增强方法解耦成一个单独的类 `UserServiceBeforeAdvice`, invoke中只利用反射调用增强方法。调用advice中的before方法,传入对应的参数信息,advice.before则是用于自己实现MethodBeforeAdvice接口后做的相应处理(增强方法), 这部分都是配置在spring.xml中,并且包含嵌套关系 【代理工厂】 ①`ProxyFactory`:工厂类,传入 `AdvisedSupport` 包装类,根据 ProxyTargetClass 属性调用不同的动态代理方法,对外提供getProxy方法用于返回代理对象 【将自动代理创建者融入Bean的生命周期】 ①`AdvisedSupport`:包装类,新增了布尔类型的proxy TargetClass代理配置属性,默认false ②`InstantiationAwareBeanPostProcessor`:继承 `BeanPostProcessor` 接口,实现了该接口的类就具备了Bean初始化,之前修改实例化Bean的扩展信息 ③`DefaultAdvisorAutoProxyCreator`:该类是处理整个AOP代理融入到Bean生命周期中的核心类,实现 `InstantiationAwareBeanPostProcessor` 接口中的postProcessBeforeInstantiation方法,获取 `AspectJExpressionPointcutAdvisor` 中的目标对象、拦截方法、匹配器,包装创建代理对象需要的参数至 `AdvisedSupport` ,调用代理工厂,接收创建的代理对象: _a.跳过 `Advice`、`Advisor`、`Pointcut` 的子类或实现类 b.通过beanFactory获取所有AspectJExpressionPointcutAdvisor信息 c.通过 `AspectJExpressionPointcutAdvisor` 中的拦截表达式来判断该类是否需要被拦截 d.构建 `AdvisedSupport` e.通过 `ProxyFactory` 来创建代理对象_ ④`AbstractAutowireCapableBeanFactory`:createBean时校验当前beanClass,是否需要创建代理对象,即调用实现了 `InstantiationAwareBeanPostProcessor` 接口的类 `DefaultAdvisorAutoProxyCreator`,调用类中的 postProcessBeforeInstantiation方法,该方法首先会判断备案Class是否是基础设施类(即没有实现 `Advice`、 `Pointcut`、`Advisor` 这三个接口的类),如果非基础类,则包装动态代理所需的参数,构建代理对象 图片链接 []: https://images.zsxq.com/lvIpwH27v7dk6HQ--1QVyMmKnojR?imageMogr2/auto-orient/quality/100!/ignore-error/1&e=1701359999&s=vtymjjymvtmtjty&token=kIxbL07-8jAj8w1n4s9zv64FuZZNEATmlU_Vm6zD:J6XO1bUt2GqAUQ7kmgISdkXjU98= ![img_11.png](img_11.png) ##spring-step-13 自定义注解实现bean的自动化扫描注册 ①定义`@Scope` 注解,用于标记Bean对象的作用域。 ②定义`@Component`注解,用于标记是否为注册Bean,提供value属性指定BeanName. ③定义 `ClassPathScanningCandidateComponentProvider` 类,具有findCandidateComponents(String basePackage)扫描并获取指定包下的所有@Component注解下的BeanDefinition ④定义 `ClassPathBeanDefinitionScanner` 扫描包处理类,继承于 `ClassPathScanningCandidateComponentProvider` ,具有doScan(String..basePackage)扫描处理方法,主要用于扫描多个包下的BeanDefinition,之后通过自定义 注解`@Scope`以及`@Component`获取并配置其作用域和BeanName进行注册。 ⑤完善 `XmlBeanDefinitionReader`,在doLoadBeanDefinitions解析注册操作中新增对context:component-scan标 签的解析,之后调用 `ClassPathBeanDefinitionScanner`#doScan方法进行Bean注册操作。 【利用 `BeanFactoryPostProcessor` 进行占位符配置(${xxx})】 ⑥定义 `PropertyPlaceholderConfigurer` 配置类,实现 `BeanFactoryPostProcessor` 接口,在其postProcessBeanFactory方法下,处理占位符配置,首先获取所有BeanDefinition具有指定前后缀即形 如${key}的Bean属性,之后解析指定路径下的properties配置文件中相同key的值,通过replace字符串替换, 将BeanDefinition属性值变为配置文件中对应key的值。最后通过propertyValues#addPropertyValue(new PropertyValue(propertyValue.getName(),value);进行Bean属性信息的替换。 ##spring-step-14 利用BeanPostProcessor、使用注解给bean注入属性信息 @Autowired @Value @Qualifier...... ①定义` @Autowired` 注解,用于标记Bean注入的依赖对象 ②定义 `@Qualifier` 注解,用于标记Bean注入的依赖对象的具体名字。提供value属性指定具体的beanName ③定义` @Value `注解,用于标记Bean注入的属性,提供value属性指定bean具体属性值,可以是占位符,也可以是普通值。 ④定义 `StringValueResolver` 字符串解析接口,提供resolveStringValue(String)解析指定字符串的方法。解析@Value注入属性 ⑤完善 `ConfigurableBeanFactory` 工厂配置化接口,新增addEmbeddedValueResolver(StringValueResolver)添加字符串解析器以及 resolveEmbeddedValue(String)解析指定字符串的方法。 ⑥完善 `AbstractBeanFactory` ,实现 `ConfigurableBeanFactory` 新增的添加字符串解析器以及解析指定字符串的方法。 ⑦完善 `PropertyPlaceholderConfigurer` 配置类,新增 `PlaceholderResolvingStringValueResolver` 内部类,实现 `StringValueResolver` 接口的resolveStringValue(String)方法。该配置类利用 BeanFactoryPostProcessor 在Bean定 义加载完之后执行的特点,在处理完XML文件的属性之后,将其解析操作通过PlaceholderResolvingStringValueResolver内部类封装并通过 beanFactory#addEmbeddedValueResolver(StringValueResolver)添加字符串解析器。 【解析自定义注解】 完善 `InstantiationAwareBeanPostProcessor` 接口,新增postProcessPropertyValues在填充属性之前执行的方法。 定义 `AutowiredAnnotationBeanPostProcessor` 类,实现 `InstantiationAwareBeanPostProcessor`,`BeanFactoryAware` 接口, 在实现的postProcessPropertyValues方法中,通过获取beanClass的Field,扫描并解析其 @Value 注解,经过beanFactory#resolveEmbeddedValue(value)解析, 设置其属性值BeanUtil.setFieldValue(),扫描 @Autowired 以及 @Qualifier 并获取到与Field.Type同类型的bean设置其依赖对BeanUtil.setFieldValue(). 【扩展Bean的生命周期】 完善 `AbstractAutowireCapableBeanFactory` 的createBean方法,在其填充Bean属性之前,检索是否存在 `InstantiationAwareBeanPostProcessor`,并调用其 postProcessPropertyValues进行Bean属性的注解注入。 Tips:postProcessPropertyValues方法调用后,可能还存在无注解的属性值,因此需要进行判断pvs是否为空,并将其添加到BeanDefinition中。 完善 `ClassPathBeanDefinitionScanner` 的doScan方法,在其注册BeanDefinition之后,注册 AutowiredAnnotationBeanPostProcessor,就不用手动去配置XML文件了。 图片链接 https://images.zsxq.com/FudSTqdIaRLo6ZbS4yjq-PxWbLj1?imageMogr2/auto-orient/quality/100!/ignore-error/1&e=1701359999&s=vtymjjymvtmtjty&token=kIxbL07-8jAj8w1n4s9zv64FuZZNEATmlU_Vm6zD:zrm6HCeWXmOYWqPn_p0HSupVOXg= ##spring-step-15 给代理对象的属性设置属性值 【通过调整AOP代理对象的创建时机,实现属性注入】 之前代理对象的生成是在Bea对象创建之前,即不在Bean的生命周期,无法实现属性的注入,现在需要调整其生成时机,整个流程其实十分简单,迁移之前AOP代理方法到BeanPostProcessor的 postProcessAfterInitialization的方法,这样在bean属性注入并初始化之后,就会调用其代理方法来完成AOP代理。之前的AOP代理类创建流程: ![img_18.png](img_18.png) ![img_12.png](img_12.png) ![img_13.png](img_13.png) ![img_14.png](img_14.png) 调整AOP代理对象的创建到postProcessAfterInitialization方法后: ![img_19.png](img_19.png) ![img_15.png](img_15.png) ![img_16.png](img_16.png) 因为此时代理对象的生成是在Bean实例化,之后,所以DefaultAdvisorAutoProxyCreator配置TargetSource需将 targetSource new TargetSource(beanClass.getDeclaredConstructor().newInstance()); 修改为targetSource=new TargetSource(bean);,否则将代理新的实例化对象,从而导致属性无法注入。 这里很好体现了IOC、AOP中postProcessBeforeInstantiation和postProcessAfterInstantiation在Bean生命周期里的具体区别,因为 postProcessBeforeInstantiation确实是可以注入配置的属性,但是对实现了AOP功能的Bean来说,属性的配置就 要放在postProcessAfterInstantiation里面实现,因为要创建代理对象来替代Bean,不能影响Bean除了AOP以外其它的功能。 ![img_17.png](img_17.png) ##spring-step-16 三级缓存解决循环依赖 ①定义 `ObjectFactory` 函数式接口,用于获取三级缓存singletonFactories的代理对象。 ②完善 `DefaultSingletonBeanRegistry`,增加singletonObjects一级缓存,earlySingletonObjects二级缓存,singletonFactories三级缓存。 并提供getSingleton获取有效缓存中的对象,registerSingleton注册单例对象addSingletonFactory添加三级缓存的方法。 ③完善 `InstantiationAwareBeanPostProcessor` ,定义一个default普通方法getEarlyBeanReference,返回一个bean并供 DefaultAdvisorAutoProxyCreator 实现。 ④完善 `DefaultAdvisorAutoProxyCreator`,增加earlyProxyReferences列表,用于记录原始对象是否已经代理, 实现InstantiationAwareBeanPostProcessor.getEarlyBeanReference方法,生成代理对象并记录,修改 postProcessAfterInitialization方法,判断earlyProxyReferences是否存在当前对象,若存在,则表示已经提前代理,则直接返回。 ⑤完善 `AbstractAutowireCapableBeanFactory`,在createBean实例化Bean之后添加三级缓存 addSingletonFactory(beanName,()->getEarlyBeanReference(beanName,beanDefinition,finalBean));最后判断单例时,调用getSingleton根据实际情况返回对象,最终注入一级缓存中。 singletonObjects一级缓存:缓存某个beanName对应的经过了完整生命周期的bean,earlySingletonObjects二级缓存:缓存提前拿原始对象进行了AOP之后得到的代理对象, 原始对象还没有进行属性注入和后续的BeanPostProcessor等生命周期 ;singletonFactories三级缓存:缓存的是一个ObjectFactory,主要用来去生成原始对象进行了AOP之后得到的代理 对象,在每个Bea的生成过程中,都会提前暴露一个工厂,这个工厂可能用到,也可能用不到,如果没有出现循环 依赖那么这个工厂无用,bean按照自己的生命周期执行,执行完后直接放入singletonObjects中即可,如果出现了循 环依赖A依赖B,则A执行ObjectFactory提交得到一个AOP之后的代理对象(如果有AOP的话,如果无需AOP,则直接得到一个原始对象。 ![img_20.png](img_20.png) https://images.zsxq.com/lsmKlVYKx1zGVGfsQNKCKAeKl5kK?imageMogr2/auto-orient/quality/100!/ignore-error/1&e=1701359999&s=vtymjjymvtmtjty&token=kIxbL07-8jAj8w1n4s9zv64FuZZNEATmlU_Vm6zD:kgoxrYm50HFolxDHJPRz_Ctqd4U= 【只有二级缓存能不能解决循环依赖】 答案是可以的,即在首次获取bean时将早期引用的bean(半成品)放入二级缓存,这边当B类填充属性时就直接从二级缓存中获取这个半成品的bean A, 最终同样也能得到完整bean A/B。但是这种情况无法解决带有AOP的循环依赖,因为此时无法判定处于二级缓存中的bean是否有被别人使用,在三级缓存的场景下, 只有早期的bean被别人使用的情况下才会从三级缓存提升到二级缓存,如今只有一、二级缓存,可能导致一个半成品bean被别人使用了, 但是这个bean最终初始化后是一个代理增强的bean,导致别人使用的bean和最终的bean不一致。 【三级缓存如何处理带有AOP的循环依赖】 允许提前暴露早期bean的条件下,实例化阶段会把一个仅分配了内存引用地址的早期bean放入到三级缓存中,当这个bean未完成创建的情况下, 被别人使用了(依赖),则会将这个半成品bean从三级缓存提升到二级缓存。当这个继续走创建流程到初始化阶段时,beanPostProcessor会判断该bean是否需要进行代理增强, 然后会将初始化结束后的bean与二级缓存中提前暴露的bean进行对比是否同一个bean,若不同,则说明二级缓存中提前暴露且已被别人使用的bean与最终初始化生成的bean不一致, 默认是会抛出异常的。以此来预防因使用了不一致的bean而导致的不可预期的错误。 ##spring-step-17 数据类型转换 【类型转换接口】 1.1 `Converter` 转换器,提供类型转换方法。 1.2 `ConverterFactory` 转换工厂,用于获取转换器。 1.3 `ConverterRegistry` 转换注册中心,用于服务注册转换器、转换工厂。 1.4 `ConverterService` 转换服务,提供判断类型能否转换以及转换方法。 1.5 `GenericConverter` 通用转换器,门面接口,并有一个内部类 `ConvertiblePair`,包装源类型与目标类型。 【类型转换服务】 2.1 `GenericConversionService`, 实现 `ConverterRegistry`, `ConverterRegistry` 接口,并添加根据转换器或工厂生成对应类型的ConvertiblePair以及遍历源和目标一系列超类的所有组合,获取转换器 的方法辅助,设有内部类ConverterFactoryAdapter,ConverterAdapter实现GenericConverter,用于适配通用转换器,方便注册及调用。 2.2 `DefaultConversionService`,继承 `GenericConversionService`,通过构造函数注册内置的类型转换器或工厂,并对外作为一个注册中心使用。 【融入Bean的生命周期】 3.1类型转换工厂 `ConversionServiceFactoryBean`,实现 `FactoryBean`,`InitializingBean`,这样在其初始化时就可以 注册类型转换器、工厂。 3.2通过ConfigurableBeanFactory添加设置、获取类型转换服务方法,由AbstractBeanFactory实现,使得在刷新容器实例化单例对象前,可以优先获取到 ConversionServiceFactoryBean, 并设置beanfactory的类型转换服务;并在AbstractAutowireCapableBeanFactory的createBean属性填充前增加类型转换的操作。 Tips:为了功能完整性,在AutowiredAnnotationBeanPostProcessor处理@Value属性填充前也应加入类型转换的操作。 https://images.zsxq.com/FuJuPjLq4Gs8NyY6AmxgkdDCrY4S?imageMogr2/auto-orient/quality/100!/ignore-error/1&e=1701359999&s=vtymjjymvtmtjty&token=kIxbL07-8jAj8w1n4s9zv64FuZZNEATmlU_Vm6zD:8ROn_lhUuK-v2KFd9Gu8tcc5Y04= https://images.zsxq.com/lpJ-Bot86lJlxZUBFwifNfgz9fZo?imageMogr2/auto-orient/quality/100!/ignore-error/1&e=1701359999&s=vtymjjymvtmtjty&token=kIxbL07-8jAj8w1n4s9zv64FuZZNEATmlU_Vm6zD:FTpT_BMDcFln3SUWwRXdiR3lVRg=