Spring的refresh源码解读整理

Spring的控制反转IOC

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

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实例,描述有哪些属性值,构造器描述更多的实现
在这里插入图片描述
先把定义信息读取到容器当中,beanDefinationRegistry就是存放beanDefination,由当前接口的一个实现子类beanDefinationReader,读取完毕后放入beanDefination
在这里插入图片描述IOC已经包含了bean的定义信息,该进行当前对象的一个实例化操作

在这里插入图片描述
BeanFactoryPostProcessor进行一些增强或者说扩展操作,例如:当读取这些bean时,还未实例化,只想把bean的名字打印出来,或者进行一些操作
下面是代码实例:
在这里插入图片描述
看一个springboot的注解实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

提出问题:

1、FactoryBean和BeanFactory的区别:FactoryBean实现了三个方法 isSingleton(是否是单例),getObject,getObjectType 就是生产一个特殊的对象相当于一个扩展bean。
创建对象的时候有两种方式一般情况下常规对象就是BeanFactory,但是有某些特殊对象可以用FactoryBean来实现,当时用FactoryBean的时候可以在getObject的地方可以做想要的操作。
在这里插入图片描述

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

Spring的IOC 源码详细分析

1、第一步在这里插入图片描述
2、进入第一层所作的核心事件
在这里插入图片描述

super(parent);调用父类的对应构造方法,父类构造方法并不是白创建的,(看源码时要看这个类对应的类图)一层一层的继承,是在往父类的构造方法里设置属性值
在这里插入图片描述

2、setConfigLocations(configLocations);

设置配置文件的路径
1)先创建一个标准环境变量 standardEnvironment
2)调用父类的一个AbstractEnvironment构造方法
3)调用父类构造方法时候,会调用一个customizePropertySource方法,这个时候这个方法是空的实际上调用的是子类的方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4 重点Spring的refresh方法

执行循序:
在这里插入图片描述

概览

该方法是 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(); 只是做了一些准备工作

在这里插入图片描述
后面需要用到earlyApplicationEvents这个集合,作为保存容器的一些早起事件
在这里插入图片描述

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

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

  1. 创建解析的一个Reader,
  2. 往当前的reader对象当中设置环境,
    3)) 设置resourceLoader资源加载器,当前的这个对象
  3. 设置entityResolver用户的一个处理器
  4. initBeanDefinitionReader初始化
  5. 重点 loadBeanDefinitions 重载
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    把xml的string变成encodedResource进行了很多次的转化
    在这里插入图片描述
    在这里插入图片描述
    document有节点,可以获取xml当中对性的节点信息
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    循环取值,判断是否为Element类型,不是的话跳过,是的话转成element,判断这个element里面是否是默认的nameSpace(命名空间)
    在这里插入图片描述
4.3)prepareBeanFactory(beanFactory); 准备bean工厂,上一步只是加载了bean的定义信息

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

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

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

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

这段代码重复处理逻辑很多
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
processBean用来记录已经执行过的bean

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

initMessageSource();
创建priorityOrderedPostProcessor、internalPostProcessors、orderedPostProcessorNames、nonOrderedPostProcessorNames的list集合,下面进行每一个集合的循环,循环的时候进行注册
在这里插入图片描述

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谁先赋值谁后赋值是解决不了问题的
在这里插入图片描述

b对象里有A的属性
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当前对象为空不是正在创建的状态
在这里插入图片描述
这个集合当中包含了正在创建的所有对象

三级缓存就是三个map结构
在这里插入图片描述
一级缓存跳到二级缓存有两个条件:1、一次缓存没有 2、当前对象是一个正在创建的状态
创建对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
相当于往三级缓存放入一个实例化的A对象
在这里插入图片描述
属性填充的过程
在这里插入图片描述
beanName:a名称; mbd:bean定义信息; bw:包装类; pvs:A里面对B的填充;
在这里插入图片描述
这个时候b是没有的
判断B是否属于这个类型
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在走一遍getSingleton方法的从一级缓存当中获取,是没有的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
之后在进行一个applyPropertyValues 在进行一遍这样的过程,这个时候pvs为a
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
先获取类型,然后去bean工厂拿a
在这里插入图片描述
拿不到a然后进行getBean
在这里插入图片描述
然后doGetBean再次进行getSingleton,这是一级缓存当中没有,a这时候是在创建中,进入判断体内,去二级缓存当中取a,没有;allowEarlyReference恒为true进入判断体,去三级缓存当中拿到了;取到了之后getObject执行内部类,返回一个Object;a 放入二级缓存;移除三级缓存中的a
在这里插入图片描述
执行内部类
在这里插入图片描述
执行完后返回
在这里插入图片描述
return bean
在这里插入图片描述
b取a已取到
在这里插入图片描述
value这个时候已经有a了,剩下的是将a的属性给b的成员变量
在这里插入图片描述
在这里插入图片描述
b的初始化完成,会调用一些beanFactory的postProcessor如before、after、init method
在这里插入图片描述
对象暴露出去
在这里插入图片描述
b放入一级缓存,三级缓存把b移除,二级缓存放的是a,但是a正在初始化还未完成初始化
在这里插入图片描述
返回b
在这里插入图片描述
返回b之后,把b给到a
在这里插入图片描述
在这里插入图片描述
把a对象移植到一级缓存中
在这里插入图片描述
这个时候循环依赖问题已解决
实例化和初始化分开来操作,将实例化好的对象提前暴露出去之后,可以拿到当前对象的引用,只不过当前对象不是一个完整状态,是实例化完成但不是初始化完成。
这时候 a b已经创建完成
在这里插入图片描述

4.12) finishRefresh

完成bean创建和初始化过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知。
在这里插入图片描述

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

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

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

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

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

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

回顾

在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`refresh()` 是 Spring 框架中的一个方法,它用于刷新应用程序上下文(ApplicationContext)以更新其内部状态。在 Spring 框架中,`refresh()` 方法是非常重要的,因为它负责完成应用程序上下文的初始化和配置,并准备好所有的单例 bean 以供使用。 下面是 `refresh()` 方法的主要流程: 1. 准备刷新过程中需要用到的变量和标志位; 2. 调用 `prepareRefresh()` 方法,进行一些预处理工作; 3. 调用 `obtainFreshBeanFactory()` 方法,创建 BeanFactory 并进行一些初始化工作; 4. 调用 `prepareBeanFactory(beanFactory)` 方法,对 BeanFactory 进行一些后续处理; 5. 调用 `postProcessBeanFactory(beanFactory)` 方法,对 BeanFactory 进行后置处理; 6. 调用 `invokeBeanFactoryPostProcessors(beanFactory)` 方法,执行 BeanFactoryPostProcessor 的 postProcessBeanFactory() 方法; 7. 调用 `registerBeanPostProcessors(beanFactory)` 方法,注册 BeanPostProcessor 实例; 8. 调用 `initMessageSource()` 方法,初始化 MessageSource 组件; 9. 调用 `initApplicationEventMulticaster()` 方法,初始化 ApplicationEventMulticaster 组件; 10. 调用 `onRefresh()` 方法,进行一些自定义的刷新工作; 11. 调用 `registerListeners()` 方法,注册事件监听器; 12. 调用 `finishBeanFactoryInitialization(beanFactory)` 方法,完成所有非延迟初始化的单例 bean 的初始化工作; 13. 调用 `finishRefresh()` 方法,完成上下文的刷新工作。 需要注意的是,`refresh()` 方法在执行过程中会涉及到很多细节,比如如何处理环境变量、如何处理自定义的 bean 定义、如何处理多个上下文之间的关系等等。如果需要深入了解 `refresh()` 方法的实现细节,可以查看 Spring 框架的源代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值