Spring的refresh源码解读整理

文章预览:

    • Spring的控制反转IOC
      • 手写一个反射实现@Autowire
        • case1:最基本的方法
        • case2:注解方法
    • IOC容器:
        • 提出问题:
    • Spring的IOC 源码详细分析
        • 2、setConfigLocations(configLocations);
        • 3、setConfigLocations 进行外部引入的配置文件的读取
        • 4 重点Spring的refresh方法
        • 概览
          • 4.1) prepareRefresh(); 只是做了一些准备工作
          • 4.2) obtainFreshBeanFactory(); 创建beanFactory,解析配置文件,生成beanDefination
          • 4.3)prepareBeanFactory(beanFactory); 准备bean工厂,上一步只是加载了bean的定义信息
          • 4.4)postProcessBeanFactory(beanFactory); 空的留给子类进行扩展
          • 4.5)invokeBeanFactoryPostProcessors(beanFactory); 执行bean工厂的处理器 实例化并且执行
          • 4.6)registerBeanPostProcessors(beanFactory);实例化并注册所有的bean
          • 4.7) initMessageSource() 初始化消息资源 国际化
          • 4.8)initApplicationEventMulticaster();进行相关事件的发布 初始化 广播器
          • 4.9) onRefresh(); 方法是空的可以进行扩展实现
          • 4.10) registerListeners();注册监听器
          • 4.11) finishBeanFactoryInitialization(beanFactory); 重点 循环依赖
          • 4.12) finishRefresh
        • 提出问题:
          • 只有一级缓存能否解决该问题?一级缓存是用来方便获取对象的
          • 添加三级缓存的意义是什么?为什么要用三级缓存
        • AOP源码解读 AOP需要看懂原生的jdbk和cglib
    • 回顾

Spring的控制反转IOC

帮我们创建当前的对象,把对象交给spring,工厂模式工厂可以帮我们生产这些对象,工厂的这些类依旧需要手动去定义
技术的更新迭代最重要的一个目的就是 偷懒
springIOC容器可以放入bean对象,还可以放集合框架,在spring当中选择的是Map,因为当我们创建完成的时候,map是一个k-v键值对的方式,我们可以根据我们的key很方便的获取到value.
容器的底层原理是反射
Spring的refresh源码解读整理_第1张图片

spring当中用的最多的一个注解 @Autowire

手写一个反射实现@Autowire

case1:最基本的方法

将userService注入userController中

package com.example.demo.basejavalearn.reflect.case1;

/**
 * @author fancc
 * @date 2022年01月28日 15:56
 */
public class UserController {

    private UserService userService;
    //如果没有@Autowire最简单的一种方式通过对userService进行get set方法

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

userService

package com.example.demo.basejavalearn.reflect.case1;

/**
 * @author fancc
 * @date 2022年01月28日 15:56
 */
public class UserService {
}

注入

package com.example.demo.basejavalearn.reflect.case1;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author fancc
 * @date 2022年01月28日 15:59
 */
public class Test {
    public static void main(String[] args) throws Exception{
        //1 先要获取大写的class类
        UserController userController = new UserController();
        //2 因为要注入useService对象,所以先把userService创建出来
        UserService userService = new UserService();
        System.out.println(userService);
        // 获取到class对象,因为反射的时候必然用到class
        /***
         * 获取class有三种方式:
         * 第一种: class.forName
         * 第二种:类.class
         * 第三种: 对象.getClass
         */
        Class<? extends UserController> clazz = userController.getClass();
        //获取想要注入的成员变量或者说属性的名称
        Field serviceField = clazz.getDeclaredField("userService");
        //当我拿到当前的这个field之后,可以通过set方法,往里边写入,这意味着要获取当前的set方法,
        // 而这个set方法是根据我们的当前的属性的名字加上一个set得到的
        //先把名字给拿到  获取属性的名称
        String name = serviceField.getName();
        //获取set方法的名称
        name = "set" + name.substring(0,1).toUpperCase()+name.substring(1,name.length());
        //获取set方法对象 传递对应的参数
        Method method = clazz.getDeclaredMethod(name, UserService.class);
        //执行set方法 放入对应的类,放入对应的类对象
        method.invoke(userController,userService);
        //执行成功 打印
        System.out.println(userController.getUserService());
    }
}

输出结果

com.example.demo.basejavalearn.reflect.case1.UserService@1c20c684
com.example.demo.basejavalearn.reflect.case1.UserService@1c20c684

case2:注解方法

1、创建一个自定义注解

package com.example.demo.basejavalearn.reflect.case2;

import java.lang.annotation.*;

/**
 * @author fancc
 * @date 2022年02月07日 10:40
 */
//注解需要实现最基本的四个元注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//作用范围是什么
@Inherited //是否可以被继承实现
@Documented //是否在文档里面展示
public @interface Autowired {
}

userController

package com.example.demo.basejavalearn.reflect.case2;

/**
 * @author fancc
 * @date 2022年02月07日 10:44
 */
public class UserController {
    @Autowired
    private UserService userService;

    public UserService getUserService(){
        return userService;
    }
}

userService

package com.example.demo.basejavalearn.reflect.case2;

/**
 * @author fancc
 * @date 2022年02月07日 10:45
 */
public class UserService {
}

实现

package com.example.demo.basejavalearn.reflect.case2;

import java.lang.reflect.Field;
import java.util.stream.Stream;

/**
 * @author fancc
 * @date 2022年02月07日 10:45
 */
//用反射的机制进行最基本的一个实现
public class Test2 {

    public static void main(String[] args) {
        UserController userController = new UserController();
        //获取userController里面对应的属性都有哪些
        Class<? extends UserController> clazz = userController.getClass();
        //获取所有的属性值
        //Field[] fields = clazz.getDeclaredFields();
        Stream.of(clazz.getDeclaredFields()).forEach(field -> {
            //开始遍历每一个属性值,当发现其中的属性值被Autowire修饰的时候,需要进行注入
                    Autowired annotation = field.getAnnotation(Autowired.class);
                    if (annotation != null){
                        //当前是可访问的对象
                        field.setAccessible(true);
                        //获取到类型,方便进行具体对象的创建
                        Class<?> type = field.getType();
                        try {
                            Object o = type.newInstance();
                            //当有了对象的时候,传入具体的对象和值
                            field.set(userController,o);
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }

                    }
                });
        System.out.println(userController.getUserService());
    }
}

IOC容器:

beanDefination描述一个bean实例,描述有哪些属性值,构造器描述更多的实现
Spring的refresh源码解读整理_第2张图片
先把定义信息读取到容器当中,beanDefinationRegistry就是存放beanDefination,由当前接口的一个实现子类beanDefinationReader,读取完毕后放入beanDefination
Spring的refresh源码解读整理_第3张图片IOC已经包含了bean的定义信息,该进行当前对象的一个实例化操作

Spring的refresh源码解读整理_第4张图片
BeanFactoryPostProcessor进行一些增强或者说扩展操作,例如:当读取这些bean时,还未实例化,只想把bean的名字打印出来,或者进行一些操作
下面是代码实例:
Spring的refresh源码解读整理_第5张图片
看一个springboot的注解实现
Spring的refresh源码解读整理_第6张图片
Spring的refresh源码解读整理_第7张图片
Spring的refresh源码解读整理_第8张图片
Spring的refresh源码解读整理_第9张图片

Spring的refresh源码解读整理_第10张图片
Spring的refresh源码解读整理_第11张图片
Spring的refresh源码解读整理_第12张图片
错误的查看方法,不应该从注解入手
正确的方法:
getCandidateConfigurations()这个方法,是什么时候开始调用的?从这个方法往上面看,spring有一个reflash方法里面有一个执行beanFactoryPostProcessor的类,这个类里面会解析import注解。
整个的注解从外面根注解开始,是怎么取到这些注解,怎么取到这些类,通过这个类是如何导入进去,为什么要执行get方法,需要把这个东西讲清楚。
有了beanFactory可以进行一个反射实现,有了反射实现正常情况下应该进行当前bean的一个实例化和初始化,在进行的这个过程引入了一个新的接口方法BeanPostProcessor(AOP也是在这块实现的BeanPostProcessor)
Spring的refresh源码解读整理_第13张图片

提出问题:

1、FactoryBean和BeanFactory的区别:FactoryBean实现了三个方法 isSingleton(是否是单例),getObject,getObjectType 就是生产一个特殊的对象相当于一个扩展bean。
创建对象的时候有两种方式一般情况下常规对象就是BeanFactory,但是有某些特殊对象可以用FactoryBean来实现,当时用FactoryBean的时候可以在getObject的地方可以做想要的操作。
Spring的refresh源码解读整理_第14张图片

2、如果想要在spring运行的不同阶段做不同的事情,应该怎么处理?
观察者模式:监听器(监听事件)

Spring的IOC 源码详细分析

1、第一步Spring的refresh源码解读整理_第15张图片
2、进入第一层所作的核心事件
Spring的refresh源码解读整理_第16张图片

super(parent);调用父类的对应构造方法,父类构造方法并不是白创建的,(看源码时要看这个类对应的类图)一层一层的继承,是在往父类的构造方法里设置属性值
Spring的refresh源码解读整理_第17张图片

2、setConfigLocations(configLocations);

设置配置文件的路径
1)先创建一个标准环境变量 standardEnvironment
2)调用父类的一个AbstractEnvironment构造方法
3)调用父类构造方法时候,会调用一个customizePropertySource方法,这个时候这个方法是空的实际上调用的是子类的方法
在这里插入图片描述
Spring的refresh源码解读整理_第18张图片
Spring的refresh源码解读整理_第19张图片
Spring的refresh源码解读整理_第20张图片
Spring的refresh源码解读整理_第21张图片
Spring的refresh源码解读整理_第22张图片

3、setConfigLocations 进行外部引入的配置文件的读取

Spring的refresh源码解读整理_第23张图片
Spring的refresh源码解读整理_第24张图片
Spring的refresh源码解读整理_第25张图片
Spring的refresh源码解读整理_第26张图片

4 重点Spring的refresh方法

执行循序:
Spring的refresh源码解读整理_第27张图片

概览

该方法是 Spring Bean 加载的核心,它是 ClassPathXmlApplicationContext 的父类 AbstractApplicationContext 的一个方法 , 顾名思义,用于刷新整个Spring 上下文信息,定义了整个 Spring 上下文加载的流程。
先看下refresh()方法总体

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
    // 准备预处理:记录容器的启动时间startupDate, 标记容器为激活,初始化上下文环境如文件路径信息,验证必填属性是否填写 
    this.prepareRefresh();
    // **告诉子类去刷新bean工厂,此方法解析配置文件并将bean信息存储到beanDefinition中,注册到BeanFactory(但是未被初始化,仅将信息写到了beanDefination的map中)**重点方法,下面的操作都基于这个beanFactory进行的
    ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
    // 设置beanFactory的基本属性:类加载器,添加多个beanPostProcesser
    this.prepareBeanFactory(beanFactory);
    try {
        // 空实现:允许子类上下文中对beanFactory做后期处理
        this.postProcessBeanFactory(beanFactory);
         /**************************以上是BeanFactory的创建及预准备工作  ****************/
        // 调用BeanFactoryPostProcessor各个实现类的方法
        this.invokeBeanFactoryPostProcessors(beanFactory);
        // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
         // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
        this.registerBeanPostProcessors(beanFactory);
        //初始化ApplicationContext的MessageSource组件(资源文件),如国际化文件,消息解析,绑定等
        this.initMessageSource();
        //初始化ApplicationContext事件广播器
        this.initApplicationEventMulticaster();
        // 初始化子类特殊bean(钩子方法)
        this.onRefresh();
        // 获取所有的事件监听器,并将监听器注册到事件广播器
        this.registerListeners();
        //** 初始化所有singleton bean;**重点方法
        this.finishBeanFactoryInitialization(beanFactory);
        // 广播事件:ApplicationContext初始化完成
        this.finishRefresh();
} catch (BeansException ex) {
	if (logger.isWarnEnabled()) {
	logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
	}
		// 销毁bean
		this.destroyBeans();
		// 重置 'active' 标志.
		this.cancelRefresh(ex);
		throw ex;
			}
		}

4.1) prepareRefresh(); 只是做了一些准备工作

Spring的refresh源码解读整理_第28张图片
后面需要用到earlyApplicationEvents这个集合,作为保存容器的一些早起事件
Spring的refresh源码解读整理_第29张图片

4.2) obtainFreshBeanFactory(); 创建beanFactory,解析配置文件,生成beanDefination

判断是否有工厂,有的话清空并销毁,没有工厂进行创建,返回DefaultListableBeanFactory(后续会用到)指的是默认创建bean工厂的类,创建的工厂相当于在堆里面开辟了一块新空间,里面的属性值还未进行写;下面是进行具体地属性值,bean的定义信息的写入loadBeanDefination,写入xml bean定义信息,这个地方可以看到解析过程
在这里插入图片描述
Spring的refresh源码解读整理_第30张图片
loadBeanDefinitions可以看到xml的解析过程,

  1. 创建解析的一个Reader,
  2. 往当前的reader对象当中设置环境,
    3)) 设置resourceLoader资源加载器,当前的这个对象
  3. 设置entityResolver用户的一个处理器
  4. initBeanDefinitionReader初始化
  5. 重点 loadBeanDefinitions 重载
    Spring的refresh源码解读整理_第31张图片
    Spring的refresh源码解读整理_第32张图片
    Spring的refresh源码解读整理_第33张图片
    Spring的refresh源码解读整理_第34张图片
    Spring的refresh源码解读整理_第35张图片
    Spring的refresh源码解读整理_第36张图片
    Spring的refresh源码解读整理_第37张图片
    把xml的string变成encodedResource进行了很多次的转化
    Spring的refresh源码解读整理_第38张图片
    Spring的refresh源码解读整理_第39张图片
    document有节点,可以获取xml当中对性的节点信息
    Spring的refresh源码解读整理_第40张图片
    Spring的refresh源码解读整理_第41张图片
    Spring的refresh源码解读整理_第42张图片
    Spring的refresh源码解读整理_第43张图片
    Spring的refresh源码解读整理_第44张图片
    Spring的refresh源码解读整理_第45张图片
    循环取值,判断是否为Element类型,不是的话跳过,是的话转成element,判断这个element里面是否是默认的nameSpace(命名空间)
    Spring的refresh源码解读整理_第46张图片
4.3)prepareBeanFactory(beanFactory); 准备bean工厂,上一步只是加载了bean的定义信息

该方法主要负责对BeanFactory的预准备工作,配置beanFactory的基础属性,比如ClassLoader和一些PostProcessor等。
这个方法主要是给BeanFactory设置一些基本的属性,比如类加载器、表达式解析器、属性编辑器,注册几个单例、添加一些不用注入的接口、添加解析依赖项等。
Spring的refresh源码解读整理_第47张图片

4.4)postProcessBeanFactory(beanFactory); 空的留给子类进行扩展

主要负责在BeanFactory准备工作完成之后,beanFactory的后置处理工作;

4.5)invokeBeanFactoryPostProcessors(beanFactory); 执行bean工厂的处理器 实例化并且执行

这段代码重复处理逻辑很多
在这里插入图片描述
Spring的refresh源码解读整理_第48张图片
Spring的refresh源码解读整理_第49张图片
processBean用来记录已经执行过的bean

4.6)registerBeanPostProcessors(beanFactory);实例化并注册所有的bean

initMessageSource();
创建priorityOrderedPostProcessor、internalPostProcessors、orderedPostProcessorNames、nonOrderedPostProcessorNames的list集合,下面进行每一个集合的循环,循环的时候进行注册
Spring的refresh源码解读整理_第50张图片

4.7) initMessageSource() 初始化消息资源 国际化

初始化MessageSource组件(做国际化功能;消息绑定,消息解析);

4.8)initApplicationEventMulticaster();进行相关事件的发布 初始化 广播器
4.9) onRefresh(); 方法是空的可以进行扩展实现

模板设计模式;该方法属于钩子方法;子类重写该方法并在容器刷新的时候自定义逻辑;

4.10) registerListeners();注册监听器

注册监听器分为两部分:
1、向事件分发器注册硬编码设置的applicationListener
2、向事件分发器注册一个IOC中的事件监听器(并不实例化)

4.11) finishBeanFactoryInitialization(beanFactory); 重点 循环依赖

finishBeanFactoryInitialization主要是负责初始化单实例的bean;该方法是重点方法,bean的生命周期基本调用getBean()方法完成。
初始化所有非懒加载得对象
循环引用
A里面有B的属性,B的里面有A的属性
构造器的循环依赖是没办法解决的。因为创建A的时候的构造方法需要给B赋值,B对象创建的时候要给A赋值,A、B谁先赋值谁后赋值是解决不了问题的
Spring的refresh源码解读整理_第51张图片

Spring的refresh源码解读整理_第52张图片
Spring的refresh源码解读整理_第53张图片
Spring的refresh源码解读整理_第54张图片
Spring的refresh源码解读整理_第55张图片
Spring的refresh源码解读整理_第56张图片
Spring的refresh源码解读整理_第57张图片
Spring的refresh源码解读整理_第58张图片
当前对象为空不是正在创建的状态
Spring的refresh源码解读整理_第59张图片
这个集合当中包含了正在创建的所有对象

三级缓存就是三个map结构
Spring的refresh源码解读整理_第60张图片
一级缓存跳到二级缓存有两个条件:1、一次缓存没有 2、当前对象是一个正在创建的状态
创建对象
Spring的refresh源码解读整理_第61张图片
Spring的refresh源码解读整理_第62张图片
Spring的refresh源码解读整理_第63张图片
Spring的refresh源码解读整理_第64张图片
Spring的refresh源码解读整理_第65张图片
Spring的refresh源码解读整理_第66张图片
Spring的refresh源码解读整理_第67张图片
相当于往三级缓存放入一个实例化的A对象
Spring的refresh源码解读整理_第68张图片
属性填充的过程
Spring的refresh源码解读整理_第69张图片
beanName:a名称; mbd:bean定义信息; bw:包装类; pvs:A里面对B的填充;
Spring的refresh源码解读整理_第70张图片
这个时候b是没有的
判断B是否属于这个类型
Spring的refresh源码解读整理_第71张图片
Spring的refresh源码解读整理_第72张图片
Spring的refresh源码解读整理_第73张图片
Spring的refresh源码解读整理_第74张图片
Spring的refresh源码解读整理_第75张图片
Spring的refresh源码解读整理_第76张图片
Spring的refresh源码解读整理_第77张图片
在走一遍getSingleton方法的从一级缓存当中获取,是没有的
Spring的refresh源码解读整理_第78张图片
Spring的refresh源码解读整理_第79张图片
Spring的refresh源码解读整理_第80张图片
Spring的refresh源码解读整理_第81张图片
Spring的refresh源码解读整理_第82张图片
之后在进行一个applyPropertyValues 在进行一遍这样的过程,这个时候pvs为a
Spring的refresh源码解读整理_第83张图片
Spring的refresh源码解读整理_第84张图片
Spring的refresh源码解读整理_第85张图片
先获取类型,然后去bean工厂拿a
Spring的refresh源码解读整理_第86张图片
拿不到a然后进行getBean
Spring的refresh源码解读整理_第87张图片
然后doGetBean再次进行getSingleton,这是一级缓存当中没有,a这时候是在创建中,进入判断体内,去二级缓存当中取a,没有;allowEarlyReference恒为true进入判断体,去三级缓存当中拿到了;取到了之后getObject执行内部类,返回一个Object;a 放入二级缓存;移除三级缓存中的a
在这里插入图片描述
执行内部类
Spring的refresh源码解读整理_第88张图片
执行完后返回
Spring的refresh源码解读整理_第89张图片
return bean
Spring的refresh源码解读整理_第90张图片
b取a已取到
Spring的refresh源码解读整理_第91张图片
value这个时候已经有a了,剩下的是将a的属性给b的成员变量
Spring的refresh源码解读整理_第92张图片
Spring的refresh源码解读整理_第93张图片
b的初始化完成,会调用一些beanFactory的postProcessor如before、after、init method
Spring的refresh源码解读整理_第94张图片
对象暴露出去
Spring的refresh源码解读整理_第95张图片
b放入一级缓存,三级缓存把b移除,二级缓存放的是a,但是a正在初始化还未完成初始化
Spring的refresh源码解读整理_第96张图片
返回b
Spring的refresh源码解读整理_第97张图片
返回b之后,把b给到a
Spring的refresh源码解读整理_第98张图片
Spring的refresh源码解读整理_第99张图片
把a对象移植到一级缓存中
Spring的refresh源码解读整理_第100张图片
这个时候循环依赖问题已解决
实例化和初始化分开来操作,将实例化好的对象提前暴露出去之后,可以拿到当前对象的引用,只不过当前对象不是一个完整状态,是实例化完成但不是初始化完成。
这时候 a b已经创建完成
Spring的refresh源码解读整理_第101张图片

4.12) finishRefresh

完成bean创建和初始化过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知。
Spring的refresh源码解读整理_第102张图片

提出问题:

只有一级缓存能否解决该问题?一级缓存是用来方便获取对象的

缓存当中放的是半成品,成品
如果当前多线程环境,都从一级缓存获取数据,有可能获取到半成品,导致属性都是空的,只有一级缓存不能解决问题
只有二级缓存能否解决该问题?
能解决一级缓存中存在的问题

添加三级缓存的意义是什么?为什么要用三级缓存

如果没有三级缓存,刚开始放置的是实例化好的对象,然后缓存中有了,后面进行代理处理,生成了一个代理类。没有三级缓存会导致有的人用的是实例化好的对象有的是代理对象。这就是为什么三级缓存要用ObjectFactory,因为传递的匿名内部类最终是用来生成一个统一的对象。
如果创建的类是一个普通类,二级缓存足以,如果创建的是一个代理类,那么就会出问题!!
一级、二级放的是String、Object,三级缓存放的是String、ObjectFactory
Spring的refresh源码解读整理_第103张图片
BeanPostProcessor用来对这个类进行一些初始化的前置后置的处理
Spring的refresh源码解读整理_第104张图片
Spring的refresh源码解读整理_第105张图片
Spring的refresh源码解读整理_第106张图片
bean和beanName传进来
Spring的refresh源码解读整理_第107张图片
createProxy动态代理传入的是bean.getClass字节码文件,beanName bean的名称,specificInterceptors拦截器,new SingletonTargetSource(bean)把它包装成一个对象
Spring的refresh源码解读整理_第108张图片
对proxyFactory进行一个重新的代理,生成一个新的对象和刚才的对象已经没有关系
Spring的refresh源码解读整理_第109张图片
Spring的refresh源码解读整理_第110张图片

AOP源码解读 AOP需要看懂原生的jdbk和cglib

找到切入点
在这里插入图片描述
Aop一定是要生成代理对象的,这一定会进到postProcessAfterInitialization这个方法
Spring的refresh源码解读整理_第111张图片
进入到wrapIfNecessary里会找到createProxy
Spring的refresh源码解读整理_第112张图片
Spring的refresh源码解读整理_第113张图片
看懂下面,需要看懂jdbk动态代理和cglib动态代理
Spring的refresh源码解读整理_第114张图片
cglibAopProxy里面的getProxy方法的createEnhancer往里面设置属性值,然后设置回调函数,然后看createProxyClassAndInstance
Spring的refresh源码解读整理_第115张图片

回顾

Spring的refresh源码解读整理_第116张图片

你可能感兴趣的:(spring,java,后端)