springboot 提供的可扩展接口

一、spring 和 springboot

Spring框架提供了全面的基础架构支持。包含依赖注入和开箱即用等模块,如:Spring JDBC 、Spring MVC 、Spring Security、 Spring AOP 、Spring ORM 、Spring Test

Spring Boot 约定大于配置-----消除了设置Spring应用程序所需的XML配置

1.特点

1:创建独立的spring应用。

2:嵌入Tomcat, Jetty Undertow 而且不需要部署他们。

3:提供的"starters" poms来简化Maven配置

4:尽可能自动配置spring应用。

5:提供生产指标,健壮检查和外部化配置

6:绝对没有代码生成和XML配置要求

2.区别

2.1 Spring 是引导配置

web.xml方法的步骤:

  • Servlet容器(服务器)读取web.xml
  • web.xml中定义的DispatcherServlet由容器实例化
  • DispatcherServlet通过读取WEB-INF / {servletName} -servlet.xml来创建WebApplicationContext
  • DispatcherServlet注册在应用程序上下文中定义的bean
  • 容器搜索实现ServletContainerInitializer的类并执行
  • SpringServletContainerInitializer找到实现所有类WebApplicationInitializer
  • WebApplicationInitializer创建具有XML或上下文@Configuration类
  • WebApplicationInitializer创建DispatcherServlet的 与先前创建的上下文。
2.2 SpringBoot 有是如何配置

Spring Boot应用程序的入口点是使用@SpringBootApplication注释的类:

  • 默认情况下,Spring Boot使用嵌入式容器来运行应用程序。Spring Boot使用public static void main入口点来启动嵌入式Web服务器。它还负责将Servlet,Filter和ServletContextInitializer bean从应用程序上下文绑定到嵌入式servlet容器。
  • Spring Boot的另一个特性是它会自动扫描同一个包中的所有类或Main类的子包中的组件。
  • Spring Boot提供了将其部署到外部容器的方式。在这种情况下,我们必须扩展SpringBootServletInitializer:

外部servlet容器查找在war包下的META-INF文件夹下MANIFEST.MF文件中定义的Main-class,SpringBootServletInitializer将负责绑定Servlet,Filter和ServletContextInitializer。

2.3 打包部署

两个框架都支持Maven和Gradle等通用包管理技术。在部署方面,框架差异很大。例如,Spring Boot Maven插件在Maven中提供Spring Boot支持。它还允许打包可执行jar或war包并就地运行应用程序。

在部署环境中Spring Boot 对比Spring的一些优点包括:

  • 提供嵌入式容器支持
  • 使用命令java -jar独立运行jar
  • 在外部容器中部署时,可以选择排除依赖关系以避免潜在的jar冲突
  • 部署时灵活指定配置文件的选项
  • 用于集成测试的随机端口生成

3.springboot核心功能

  • 可独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行。
  • 内嵌的Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,无须以war包形式部署项目。
  • 简化的Maven配置:Spring提供推荐的基础 POM 文件来简化Maven 配置。
  • 自动配置Spring:Spring Boot会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置。
  • 提供生产就绪型功能:提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查。
  • 无代码生成和xml配置:Spring Boot不生成代码。完全不需要任何xml配置即可实现Spring的所有配置。

二、IOC控制反转

1.控制反转

ioc控制反转:对象的创建和销毁就都交给容器来控制,用户只关注业务需求就好;

反转:正转其实就是对象去找实例,而反转通过容器 让实例来找对象

依赖:将对象理解为Bean,bean和容器之间有个依赖关系,bean对象的创建是依赖容器的

注入:通过容器注入了bean对象,容器会自动找到和bean对象匹配的类型实例注入到对象中;

2.ioc加载过程:

二、Springboot启动流程






四、容器refresh()

  • Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息;
    • xml注册bean;
    • 注解注册Bean;@Service、@Component、@Bean、xxx
  • Spring容器会合适的时机创建这些Bean
    • 用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
    • 统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
  • 后置处理器;BeanPostProcessor
    • 每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
      AutowiredAnnotationBeanPostProcessor:处理自动注入
      AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
      xxx...
      增强的功能注解:
      AsyncAnnotationBeanPostProcessor
  • 事件驱动模型;
    • ApplicationListener;事件监听;ApplicationEventMulticaster;事件派发:
1、 prepareRefresh:准备刷新上下文环境
java 复制代码
protected void prepareRefresh() {
		// 容器启动的时间
		this.startupDate = System.currentTimeMillis();
		//容器关闭
		this.closed.set(false);
		//容器激活
		this.active.set(true);
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
		//空方法,留给子类自己去实现,
		initPropertySources();
		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		//获取系统环境对象,在进入refresh方法之前获取的 StandardEnvironment 实例对象(包含了全部的系统变量和系统属性),这里的环境对象不为空,直接将对象值返回。对属性验证
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		//创建事件监听对象
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}
		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}
扩展initPropertySources
2、 obtainFreshBeanFactory:获取告诉子类初始化Bean工厂,不同工厂有不同的实现
  • 创建beanFactory
  • 加载并解析了bean.xml为BeanDefinition保存到beanFactory
3、prepareBeanFactory(beanFactory):对bean工厂进行填充属性
  • 属性填充(设置类型加载器、EL表达式解析器,、默认的propertyEditor属性编辑器的注册器,、忽略自动装配的接口,、监听器)
  • 系统环境变量(Environment)相关的bean到一级缓存中
4、postProcessBeanFactory(beanFactory):BeanFactory准备工作完成后进行的后置处理工作

留个子类去实现该接口,bean工厂的后置处理器,子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置

====== BeanFactory的创建及预准备工作 完成 ===================

5、invokeBeanFactoryPostProcessors(beanFactory):调用bean工厂的后置处理器.

执行BeanFactoryPostProcessor的方法;BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的;

两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor。通过指定顺序, 遍历调用各种实现了BeanDefinitionRegistryPostProcessor接口或BeanFactoryPostProcessor接口, 的beanFactory后处理器

  • 执行BeanFactoryPostProcessor的方法;
    • 先执行BeanDefinitionRegistryPostProcessor
      • 获取所有的BeanDefinitionRegistryPostProcessor;
      • 看先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、postProcessor.postProcessBeanDefinitionRegistry(registry)(定位、加载、解析、注册相关注解)
      • 在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor、postProcessor.postProcessBeanDefinitionRegistry(registry)
      • 最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors;
    • 再执行BeanFactoryPostProcessor的方法 :postProcessor.postProcessBeanDefinitionRegistry(registry)
      • 获取所有的BeanFactoryPostProcessor
      • 看先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、postProcessor.postProcessBeanFactory()
      • 在执行实现了Ordered顺序接口的BeanFactoryPostProcessor、 postProcessor.postProcessBeanFactory()
      • 最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor、postProcessor.postProcessBeanFactory()(对加了@Configuration的配置类进行CGLIB增强处理(代理配置类),添加ImportAwareBeanPostProcessor后置处理类)
6、registerBeanPostProcessors(beanFactory);注册bean的后置处理器

注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】

不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的

【BeanPostProcessor、DestructionAwareBeanPostProcessor、 InstantiationAwareBeanPostProcessor、 SmartInstantiationAwareBeanPostProcessor

MergedBeanDefinitionPostProcessor【internalPostProcessors】】

  • 获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
  • 先注册PriorityOrdered优先级接口的BeanPostProcessor; 把每一个BeanPostProcessor;添加到BeanFactory中
    beanFactory.addBeanPostProcessor(postProcessor);
  • 再注册Ordered接口的
  • 最后注册没有实现任何优先级接口的
  • 最终注册MergedBeanDefinitionPostProcessor;
  • 注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是
    applicationContext.addApplicationListener((ApplicationListener<?>) bean);
7、initMessageSource();初始化国际化资源处理器.

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

  • 获取BeanFactory
  • 看容器中是否有id为messageSource的,类型是MessageSource的组件,如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
  • 把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource;
    beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
    MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);
8、initApplicationEventMulticaster();初始化事件派发器;
  • 获取BeanFactory
  • 从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
  • 如果上一步没有配置;创建一个SimpleApplicationEventMulticaster
  • 将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入
9、onRefresh();

留给子容器(子类):子类重写这个方法,在容器刷新的时候可以自定义逻辑;

10、registerListeners();容器中将所有项目里面的ApplicationListener注册进来;
  • 从容器中拿到所有的ApplicationListener
  • 将每个监听器添加到事件派发器中; getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  • 派发之前步骤产生的事件;
11、finishBeanFactoryInitialization(beanFactory);

初始化所有剩下的单实例bean;

beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean

  • 获取容器中的所有Bean,依次进行初始化和创建对象
  • 获取Bean的定义信息;RootBeanDefinition
  • Bean不是抽象的,是单实例的,是懒加载;
    • 判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
    • 不是工厂Bean。利用getBean(beanName);创建对象
      • getBean(beanName); ioc.getBean();
        • doGetBean(name, null, null, false);
        • 先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
          从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
        • 缓存中获取不到,开始Bean的创建对象流程;
        • 标记当前bean已经被创建
        • 获取Bean的定义信息;
        • 【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】

        • 启动单实例Bean的创建流程;
          • createBean(beanName, mbd, args);
            • Object bean = resolveBeforeInstantiation(beanName, mbdToUse);让BeanPostProcessor先拦截返回代理对象;
              【InstantiationAwareBeanPostProcessor】:提前执行;先触发:postProcessBeforeInstantiation(); 如果有返回值:触发postProcessAfterInitialization();
            • 如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4)
            • Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean
              • 【创建Bean实例】;createBeanInstance(beanName, mbd, args);利用工厂方法或者对象的构造器创建出Bean实例
              • applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
              • 【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper);
              • ===========
              • 赋值之前:
                • 拿到InstantiationAwareBeanPostProcessor后置处理器;postProcessAfterInstantiation();
                • 拿到InstantiationAwareBeanPostProcessor后置处理器;postProcessPropertyValues();
                • ===赋值之前:=
                • 应用Bean属性的值;为属性利用setter方法等进行赋值; applyPropertyValues(beanName, mbd, bw, pvs);
                • 【Bean初始化】initializeBean(beanName, exposedObject, mbd);
                  • 【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
                    BeanNameAware\BeanClassLoaderAware\BeanFactoryAware
                  • 【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
                    BeanPostProcessor.postProcessBeforeInitialization();
                  • 【执行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd);
                  • 是否是InitializingBean接口的实现;执行接口规定的初始化;
                  • 是否自定义初始化方法;
                  • 【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization
                    BeanPostProcessor.postProcessAfterInitialization();
                  • 注册Bean的销毁方法;
                  • 将创建的Bean添加到缓存中singletonObjects;
                    ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息;
                    所有Bean都利用getBean创建完成以后;
                    检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();
12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成;
  • initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor 默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor(); 加入到容器;写一个LifecycleProcessor的实现类,可以在BeanFactory
    void onRefresh(); void onClose();
  • getLifecycleProcessor().onRefresh(); 拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();
  • publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
  • liveBeansView.registerApplicationContext(this);

五、bean生命周期

1.BeanDefinitionReader
  • 读取配置信息。通过BeanDefinitionReader 读取指定的配置文件生成bean的定义信息,然后到完整的bean定义信息(BeanDefinition对象),

  • BeanDefinitionReder可分为以下几种:AnnotededBeanDefinitionReader、ConfigurationClassBeanDefinitionReader、ClassPathBeanDefinitionScanner

  • 这里只是存储bean的定义信息,还没有实例化bean对象;

  • 到invokeBeanFactoryPostProcessors之前已经获取到

xml 复制代码
<bean id="student" class="com.dd.controller.beanextend.Student">
        <property name="name" value="AAA"/>
        <property name="age" value="1"/>
    </bean>
    <bean id="myBeanFactoryPostProcessor" class="com.dd.controller.beanextend.MyBeanFactoryPostProcessor"/>
java 复制代码
package com.dd.controller.beanextend;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class Student {

    private String name;

    private int age;
}
java 复制代码
package com.dd.controller.beanextend;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 自定义BeanFactoryPostProcessor
 * BeanFactoryPostProcessor在容器实例化任何bean之前读取bean的定义并可以修改他
 * 可以通过实现Ordered接口指定order属性的值,从而设置BeanFactoryPostProcessor的执行顺序,order值越小,优先级越高
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("执行MyBeanFactoryPostProcessor01的postProcessBeanFactory方法");

        //获取工厂当前所有注册的beanNames
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            if(Objects.equals("student", beanDefinitionName)) {
                //获取对应的属性值
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
                MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
                //更新属性值
                if(propertyValues.contains("name")) {
                    System.out.println("修改name属性值,旧值:" + propertyValues.get("name"));
                    propertyValues.add("name", "BBB");
                }
            }
        }

    }

    @Override
    public int getOrder() {
        return 0;
    }
}
java 复制代码
package com.dd.controller.beanextend;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    @org.junit.Test
    public void test() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
        System.out.println(applicationContext.getBean("student"));
    }
}

运行结果

2 进入invokeBeanFactoryPostProcessors 方法

获取 S p r i n g 配置文件中定义的所有实现 B e a n F a c t o r y P o s t P r o c e s s o r 接口的 b e a n ,然后根据优先级进行排序 \textcolor{yellow}{获取Spring配置文件中定义的所有实现BeanFactoryPostProcessor接口的bean,然后根据优先级进行排序} 获取Spring配置文件中定义的所有实现BeanFactoryPostProcessor接口的bean,然后根据优先级进行排序

  • 首先对BeanFactoryPostProcessor的子类BeanDefinitionRegistryPostProcessor进行处理,从容器找出所有实现BeanDefinitionRegistryPostProcessor接口的Bean,然后按照优先级进行排序后,依次回调BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法;
  • 接着处理普通的BeanFactoryPostProcessor接口,同样的,从容器找出所有实现BeanFactoryPostProcessor接口的Bean,使用三个不同的集合,分别存放实现了PriorityOrdered接口、实现了Ordered接口、普通的BeanFactoryPostProcessor。接着按照优先级排序后,会执行postProcessBeanFactory()回调;
java 复制代码
// org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)
public static void invokeBeanFactoryPostProcessors(
    ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
 
    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    // 记录已经处理过的BeanFactoryPostProcessor集合,无需重复执行
    Set<String> processedBeans = new HashSet<>();
 
    // 对BeanDefinitionRegistry类型的处理
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 存放普通的BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
 
        // 存放BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
 
        // 循环遍历硬编码方式注册的BeanFactoryPostProcessor后置处理器
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // 区分普通的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,分别放入不同的集合中
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                    (BeanDefinitionRegistryPostProcessor) postProcessor;
 
                // 如果是BeanDefinitionRegistryPostProcessor的话,直接执行BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                // BeanDefinitionRegistryPostProcessor
                registryProcessors.add(registryProcessor);
            }
            else {
                // 普通BeanFactoryPostProcessor
                regularPostProcessors.add(postProcessor);
            }
        }
 
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // Separate between BeanDefinitionRegistryPostProcessors that implement
        // PriorityOrdered, Ordered, and the rest.
 
        // 记录本次要执行的BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
 
        // 配置注册的后置处理器
        // 1、调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类
 
        // 找出所有实现BeanDefinitionRegistryPostProcessor接口的Bean
        String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        // 循环遍历,判断是否实现PriorityOrdered接口
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
 
                // 添加到将要执行的集合中,避免重复执行
                processedBeans.add(ppName);
            }
        }
        // 按照优先级进行排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
 
        // 调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();
 
        // 2、调用所有实现了Ordered接口的BeanDefinitionRegistryPostProcessor实现类
 
        // 找出所有实现BeanDefinitionRegistryPostProcessor接口的类
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
 
        // 循环遍历,判断是否实现Ordered接口
        for (String ppName : postProcessorNames) {
            // 未执行过 && 实现Ordered接口
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
 
                // 添加到将要执行的集合中,避免重复执行
                processedBeans.add(ppName);
            }
        }
        // 按照order排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
 
        // 调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();
         // 3、调用所有剩下的BeanDefinitionRegistryPostProcessors
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 未执行过的
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
            // 排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
 
            // 调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
        }
 
        // 回调所有BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
 
        // 回调普通BeanFactoryPostProcessor的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }
 
    else {
        // 调用在上下文实例中注册的工厂处理器
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }
 
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!
 
    // 从bean工厂中获取到BeanFactoryPostProcessor
    //!!!!!!!!!!!!!!!!!!!!!!  huo
    String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
 
    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
 
    // 存放实现了PriorityOrdered接口的BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
 
    // 存放实现了Ordered接口的BeanFactoryPostProcessor
    List<String> orderedPostProcessorNames = new ArrayList<>();
 
    // 存放其它BeanFactoryPostProcessor
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
 
    // 循环从工厂中获取的BeanFactoryPostProcessor, 分别存入到三个不同的集合中
    for (String ppName : postProcessorNames) {
        // 针对已经处理过的BeanFactoryPostProcessor,不做任何操作,无需重复执行
        if (processedBeans.contains(ppName)) {
            // skip - already processed in first phase above
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            // PriorityOrdered接口的BeanFactoryPostProcessor
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            // Ordered接口的BeanFactoryPostProcessor
            orderedPostProcessorNames.add(ppName);
        }
        else {
            // 普通BeanFactoryPostProcessor
            nonOrderedPostProcessorNames.add(ppName);
        }
    }
    // 1、调用所有实现PriorityOrdered接口的BeanFactoryPostProcessor
 
    // 排序
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // 执行postProcessBeanFactory()回调
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
 
    // 2、调用所有实现Ordered接口的BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
        // 这里会触发BeanFactoryPostProcessor的创建流程
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    // 排序
    sortPostProcessors(orderedPostProcessors, beanFactory);
    // 执行postProcessBeanFactory()回调
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
 
    // 3、调用所有其他BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    // 执行postProcessBeanFactory()回调
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
 
    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
 
    // 清除元数据缓存
    beanFactory.clearMetadataCache();
}
java 复制代码
// 从bean工厂中获取到BeanFactoryPostProcessor
//!!!!!!!!!!!!!!!!!!!!!! 通过beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false),获取Spring配置文件中定义的所有实现BeanFactoryPostProcessor接口的bean,然后根据优先级进行排序

String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
3.bean生命周期
3.bean 生命周期

实例化,初始化,使用中(完整对象),销毁 \textcolor{green}{实例化,初始化,使用中(完整对象),销毁} 实例化,初始化,使用中(完整对象),销毁

3.1 实例化

实例化前置:

  1. 实例化前置 I n s t a n t i a t i o n A w a r e B e a n P o s t P r o c e s s o r . p o s t P r o c e s s B e f o r e I n s t a n t i a t i o n ( C l a s s < ? > b e a n C l a s s , S t r i n g b e a n N a m e ) \textcolor{green}{实例化前置 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class<?> beanClass, String beanName)} 实例化前置InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class<?>beanClass,StringbeanName)

对象实例化之前对bean对象的class信息进行修改或者扩展,底层是动态代理AOP技术实现的;是bean生命周期中最先执行的方法;

  • 返回了非空的值,那么以后我们需要用到这个bean的时候,拿到的就现在返回的对象了,也就不会去走第二步去实例化对象了;
  • 默认也是返回null值的,那么就直接返回,接下来会调用doCreateBean方法来实例化对象;
  1. 实例化对象 \textcolor{green}{实例化对象} 实例化对象
  • 进入 doGetBean(),从 getSingleton() 没有找到对象,进入创建 Bean 的逻辑
  • doCreateBean方法创建实例,反射, 只是将对象实例化了,对象内的属性还未设置;
  • 进入 doCreateBean() 后,调用 createBeanInstance()。
  • 进入 createBeanInstance() 后,调用 instantiateBean()。
  1. 实例化后置 I n s t a n t i a t i o n A w a r e B e a n P o s t P r o c e s s o r . p o s t P r o c e s s A f t e r I n s t a n t i a t i o n ( O b j e c t b e a n , S t r i n g b e a n N a m e ) \textcolor{green}{实例化后置 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName)} 实例化后置InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Objectbean,StringbeanName)

在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为他的返回值是决定要不要调用postProcessPropertyValues方法中的一个因素(因为还有一个因素是mbd.getDependencyCheck());

  • 返回false :如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;
  • 返回true : 如果返回true,postProcessPropertyValues就会被执行

4... 属性修改 I n s t a n t i a t i o n A w a r e B e a n P o s t P r o c e s s o r . P r o p e r t y V a l u e s p o s t P r o c e s s P r o p e r t y V a l u e s ( P r o p e r t y V a l u e s p v s , P r o p e r t y D e s c r i p t o r [ ] p d s , O b j e c t b e a n , S t r i n g b e a n N a m e ) \textcolor{green}{属性修改 InstantiationAwareBeanPostProcessor.PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)} 属性修改InstantiationAwareBeanPostProcessor.PropertyValuespostProcessPropertyValues(PropertyValuespvs,PropertyDescriptor[]pds,Objectbean,StringbeanName)

此方法可对属性值进行修改,修改范围包括添加、修改、删除操作;,如果实例化后置 postProcessAfterInstantiation() 方法返回false,那么该方法不会被调用;

3.2.初始化

5.给用户赋值 A b s t r a c t A u t o w i r e C a p a b l e B e a n F a c t o r y . p o p u l a t e B e a n ( ) \textcolor{green}{AbstractAutowireCapableBeanFactory.populateBean()} AbstractAutowireCapableBeanFactory.populateBean()

为 Bean 设置相关属性和依赖

  • 再回到 doCreateBean(),继续往后走,进入 populateBean() this.populateBean(beanName, mbd, instanceWrapper)。[依赖注入逻辑]
  • 进入 populateBean() 后,执行 applyPropertyValues()
  • 进入 applyPropertyValues(),执行 bw.setPropertyValues()
  • 进入 processLocalProperty(),执行 ph.setValue()。

6.给容器属性赋值 实现一些 A w a r e 接口方法 \textcolor{green}{实现一些Aware接口方法} 实现一些Aware接口方法

A l l A w a r e I n t e r f a c e \textcolor{green}{AllAwareInterface} AllAwareInterface

7.初始化前置 B e a n P o s t P r o c e s s o r . p o s t P r o c e s s B e f o r e I n i t i a l i z a t i o n ( ) \textcolor{green}{BeanPostProcessor.postProcessBeforeInitialization()} BeanPostProcessor.postProcessBeforeInitialization()

在每一个 Bean 初始化之前执行的方法(有多少 Bean 调用多少次)

注意 : 启用该方法后,标注了@PostConstruct注解的方法会失效

8.执行初始化方法 @ P o s t C o n s t r u c t \textcolor{green}{@PostConstruct } @PostConstruct

初始化方法:

  • 添加了@PostConstruct 注解的方法
  • 实现InitializingBean接口,实现afterPropertiesset()方法。
  • 在@bean注解上添加 initMethod属性

场景:预加载一部分数据,举例:要开发一个短信发送服务,在服务中,有些基本的配置信息是存放在数据库的,那么在Spring Bean初始化就需要从数据库加载到这些配置信息。

java 复制代码
//1.定义了一个普通的java类DemoService4,然后通过配置类BeanConfig的@Bean进行注入。
//2.在@Bean注入的时候,指定了初始化方法initMethod
//3.对于@PostConstruct的使用只需要在类的方法上添加注解即可。
//4.对于InitializingBean的使用需要实现接口InitializingBean中的afterPropertiesSet方法。
public class InitDemoService4 implements InitializingBean {

    @Autowired
    private Environment environment;

    public InitDemoService4(){
        System.out.println("DemoService4的构造方法打印environment="+environment);
    }

    /**
     * 使用JSR-250规范定义的@Postconstruct注解
     */
    @PostConstruct
    public void postConstruct() {
        System.out.println("DemoService4使用@postConstruct打印environment="+environment);
    }

    /**
     * 使用@Bean的init-method属性  initMethod就是原来spring配置文件里bean标签上的init-method,可以额外的@Configuration来声明一个@Bean。
     */
    public void initMethod() {
        System.out.println("DemoService4使用initMethod打印environment="+environment);
    }

    /**
     * InitializingBean接口中的方法  相当于与Spring框架深度绑定了
     * eg: MyBatis 的 SqlSessionFactoryBean
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("DemoService4使用InitializingBean打印environment=" + environment);
    }

}

调用顺序:构造函数 --> @PostConstruct --> InitializingBean接口 --> @Bean init-method

9.初始化方法一:@PostConstruct

在bean对象内添加@PostConstruct 注解后即可实现初始化的功能,被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。 有多个则会执行多次;

注意:

  • 如果spring 实现了 BeanPostProcessor接口的postProcessBeforeInitialization() 的初始后置方法,那么@PostConstruct注解会失效;

10.InitializingBean.afterPropertiesSet()

spring 初始化方法之一,作用是在BeanFactory完成属性设置之后,执行自定义的初始化行为。

执行顺序:在initMethod之前执行,在@PostConstruct之后执行

java 复制代码
@Component
public class ExtInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        // 一个 InitializingBean 执行一次
        // spring 初始化方法,作用是在BeanFactory完成属性设置之后,执行自定义的  初始化行为.
        // 执行顺序:在initMethod之前执行,在@PostConstruct之后执行
        System.out.println("InitializingBean");
    }

示例:MyBatis 的 SqlSessionFactoryBean

11.init-method

bean 配置文件属性 init-method 用于在bean初始化时指定执行方法,用来替代继承 InitializingBean接口,

注意:只有一个类完整的实例被创建出来后,才能走初始化方法。

3.3 使用中

13.使用中

bean对象就已经完全创建好了,是一个完整对象了,并且正在被其他对象使用了

3.4 销毁

14.销毁流程

被spring容器管理的bean默认是单例的,默认在类上面有个 @Scope注解

java 复制代码
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)  
多例模式也叫原型模式,它底层不是重新创建一个bean对象出来,而是使用深拷贝技术实现的,就是复制一个对象出来进行使用

(1)DisposableBean.destroy()

单例模式,会先执行 DisposableBean.destroy()方法,然后在执行 destroy-Method 方法;

(2)destory-method方法

在@Bean注解里加上 destroyMethod属性,指向销毁方法 :destroyMethod_1()

java 复制代码
@Component()
public class InitMethod  {
 
    // 在@Bean注解上添加initMethod属性,指向类中的 initMethod_1 执行初始化方法
    // 在@Bean注解上添加destroyMethod属性,指向类中的 destroyMethod_1 执行销毁方法
    @Bean(initMethod = "initMethod_1",destroyMethod = "destroyMethod_1")
    public BeanTest getBeanTest(){
        return new BeanTest();
    }

执行顺序

(1)初始化之后执行顺序: @PostConstruct > InitializingBean > Bean init-method(xml注解或者@Bean)

(2)销毁之前执行顺序:@preDestroy > DisposableBean > destroy-method(xml注解或者@Bean)

15 返回bean给用户,剩下的生命周期由用户控制

多例模式下,spring无法进行管理,所以将生命周期交给用户控制,用户用完bean对象后,java垃圾处理器会自动将无用的对象进行回收操作;

六、可扩展的接口启动调用顺序

1 ApplicationContextInitializer - 用于在刷新容器之前初始化Spring的回调接口。

o r g . s p r i n g f r a m e w o r k . c o n t e x t . A p p l i c a t i o n C o n t e x t I n i t i a l i z e r \textcolor{green}{org.springframework.context.ApplicationContextInitializer} org.springframework.context.ApplicationContextInitializer

刷新容器之前初始化ConfigurableApplicationContext的回调接口

在容器刷新之前调用此类的initialize方法。可以在整个spring容器还没被初始化之前做一些事情。

自定义初始化器:通常用于需要对应用程序上下文进行编程初始化的web应用程序中。例如,根据上下文环境注册属性源或激活概要文件。

java 复制代码
@Component
public class P implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 创建一个bean的定义类的对象
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(C.class);
        // 将Bean 的定义注册到Spring环境
        registry.registerBeanDefinition("c", rootBeanDefinition);
        //第一、先调用这个注册c
        System.out.println("postProcessBeanDefinitionRegistry----注册c");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // bean的名字为key, bean的实例为value
        // 第二、当bean都完成注册后,调用这个方法
        // 这里只是做好了bean 的定义,但是没有真正的如,初始化bean和bean的注入
        String[] strings = beanFactory.getBeanDefinitionNames();
        System.out.println("postProcessBeanFactory----start");
        for (String string : strings) {
            System.out.println(string);
        }
        System.out.println("postProcessBeanFactory----end");
    }
}
3.BeanFactoryPostProcessor - 读取配置元数据,并可以根据需要进行修改

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . c o n f i g . B e a n F a c t o r y P o s t P r o c e s s o r \textcolor{green}{org.springframework.beans.factory.config.BeanFactoryPostProcessor} org.springframework.beans.factory.config.BeanFactoryPostProcessor

beanFactory的扩展接口,调用时机在spring在读取beanDefinition信息之后,实例化bean之前。

场景 :通过实现这个扩展接口来自行处理一些东西,比如修改已经注册的beanDefinition的元信息。

(1)对敏感信息的解密处理

数据库的连接配置,redis的连接配置、shiro的加密算法、rabbitmq的连接配置等等,凡是涉及到敏感信息的,都需要进行加密处理,信息安全非常重要。

配置的时候以密文配置,在真正用到之前在spring容器中进行解密,然后用解密后的信息进行真正的操作。

(2)Spring中占位符的处理

java 复制代码
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("调用自定义BeanFactoryPostProcessor");
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("student1");
        System.out.println("开始修改属性的值");
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        propertyValues.add("name","Tom");

    }
}
4.InstantiationAwareBeanPostProcessor

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . c o n f i g . I n s t a n t i a t i o n A w a r e B e a n P o s t P r o c e s s o r \textcolor{green}{org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor} org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

该接口继承了BeanPostProcess接口,区别如下:

BeanPostProcess接口只在bean的初始化阶段进行扩展(注入spring上下文前后),而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段。

该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段:实例化阶段初始化阶段,下面一起进行说明,按调用顺序为:

  • postProcessBeforeInstantiation:实例化bean之前,相当于new这个bean之前 BeanPostProcessor可以返回一个代理对象,在doCreateBean()生成对象之前, 用户可以自定义返回一个对象。返回了一个你自己创建的bean的话,那么之后的代码就不会执行了。

实例化之后 resolveBeforeInstantiation()没有返回bean.则创建Bean,会经过**populateBean(beanName, mbd, instanceWrapper)**方法。

populateBean(beanName, mbd, instanceWrapper)依次执行postProcessAfterInstantiation() 与postProcessPropertyValues()

  • postProcessAfterInstantiation:实例化bean之后,相当于new这个bean之后, 默认返回true,什么也不做,继续下一步。
  • postProcessPropertyValues:bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现, 高版本已经过时了,使用postProcessProperties代替
  • postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前
  • postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后

场景:对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行统一的设值等等。

  • 典型的应用场景:在AOP生成代理对象的时候,AOP代理需要创建被代理类的对象,才能对对象进行代理。根据代理的特点,通过在BeanPostProcessor#postProcessAfterInitialization方法执行的时候,对被代理对象进行增强,这样就可以生成新的代理对象。

eg:

(1)AOP 就是基于 InstantiationAwareBeanPostProcessor实现的

(2)Autowired进行注入对象的时候,也是通过BeanPostProcessor完成。

(3)处理自定义注解:bean可以添加我们自定义的注解,自定义的注解处理方式在该类中实现,如通过注解识别一组或几组bean,在后续的业务处理中根据组bean进行逻辑。

(4)打印日志:将每个bean的初始化情况打印出来;打印初始化时间等

复制代码
com.dahua.evo.edu.boot.common.i18n.I18nMessageInitializer
java 复制代码
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    // 1 实例化前置
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

        System.out.println("1.postProcessBeforeInstantiation被调用了----在对象实例化之前调用-----beanName:" + beanName);
        if ("student".equals(beanName)) {
            System.out.println("before==============student1");
        }
//        Student1 postProcessBeforeInstantiation = new Student1("postProcessBeforeInstantiation", 100);
//        return postProcessBeforeInstantiation;
        // 默认什么都不做,返回null
        return null;
    }

    // 3.实例化后置
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("3.postProcessAfterInstantiation被调用了---------beanName:" + beanName);
        //默认返回true,什么也不做,继续下一步
        return false;
    }

    // 4.属性修改
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("4.postProcessPropertyValues被调用了---------beanName:"+beanName);
        // 此方法可对bean中的属性值进行、添加、修改、删除操作;
        // 对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用,
        System.out.println("属性修改。。。。。。");
        System.out.println(bean);


        MutablePropertyValues mutablePropertyValues = new MutablePropertyValues(pvs);
        List<PropertyValue> propertyValueList = mutablePropertyValues.getPropertyValueList();
        PropertyValue pv = new PropertyValue("age", 999);
        propertyValueList.add(pv);

        return mutablePropertyValues;
    }

    /**
     * 在每一个 Bean 初始化之前执行的方法(有多少 Bean 调用多少次)
     * 注意 : 启用该方法后,标注了@PostConstruct注解的方法会失效
     */
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
//        System.out.println("postProcessBeforeInstantiation被调用了----在对象实例化之前调用-----beanName:" + o);
//        if (o.getClass().getSimpleName().equals("student1")) {
//            System.out.println("before==============student1");
//        }
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        return null;
    }
}
5.SmartInstantiationAwareBeanPostProcessor - 确定执行哪一个构造方法

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . c o n f i g . S m a r t I n s t a n t i a t i o n A w a r e B e a n P o s t P r o c e s s o r \textcolor{green}{org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor} org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

扩展接口有3个触发点方法:

5.1 predictBeanType**

该触发点发生在postProcessBeforeInstantiation之前,这个方法用于预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。

​ BeanFactory.getType(name)时当通过Bean定义无法得到Bean类型信息时就调用该回调方法来决定类型信息;

​ BeanFactory.isTypeMatch(name, targetType)用于检测给定名字的Bean是否匹配目标类型(如在依赖注入时需要使用)。

5.2 determineCandidateConstructors

检测Bean的构造器,可以检测出多个候选构造器,再由相应的策略决定使用哪一个,如AutowiredAnnotationBeanPostProcessor实现将自动扫描通过@Autowired/@Value注解的构造器从而可以完成构造器注入

触发点:

​ 该触发点发生在postProcessBeforeInstantiation之后, 对象实例化之前执行。用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。

使用:

​ 当一个bean中有两个构造方法的时候,一个无参构造方法,一个有参构造方法,那么spring在进行bean初始化的时候回默认调用无参的构造方法:

​ 如果我们想要执行有参的构造方法,则需要在有参构造方法上面加上@Autowired注解即可:

在这个过程中,如果推断出有一个构造方法加了@Autowired注解,那么spring会把它放到一个临时变量当中,在判断临时变量是否为空,如果不为空,则把这个变量转换成临时数组返回出去,而如果构造方法都没有加@Autowired注解,那么spring就无法判断要把哪个加入到临时变量中,所以最后返回一个null,然后spring根据返回的null来使用默认的构造方法。

5.3 getEarlyBeanReference

获得提前暴露的bean引用,主要用于解决循环引用的问题.

该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

java 复制代码
//AutowiredAnnotationBeanPostProcessor 使用
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException {
        if (!this.lookupMethodsChecked.contains(beanName)) {
            try {
                ReflectionUtils.doWithMethods(beanClass, new MethodCallback() {
                    public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                        Lookup lookup = (Lookup)method.getAnnotation(Lookup.class);
                  ................
大致步骤:
(1)获取类的所有构造方法

(2)遍历构造方法

- 只有一个无参构造方法, 则返回null。

- 只有一个有参构造方法, 则返回这个构造方法。

- 有多个构造方法且没有@Autowired, 此时spring不知道使用哪一个了. 当选择不了的时候, 干脆返回 null。

- 有多个构造方法, 且在其中一个方法上标注了 @Autowired , 则会返回这个标注的构造方法

- 有多个构造方法, 且在多个方法上标注了@Autowired, 则spring会抛出异常。
6.BeanFactoryAware

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . B e a n F a c t o r y A w a r e \textcolor{green}{org.springframework.beans.factory.BeanFactoryAware} org.springframework.beans.factory.BeanFactoryAware

java 复制代码
public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory var1) throws BeansException;
}

这个类只有一个触发点,发生在bean的实例化之后,注入属性之前,也就是Setter之前。这个类的扩展点方法为setBeanFactory,可以拿到BeanFactory这个属性。

场景:在bean实例化之后,初始化之前,拿到 BeanFactory,可以对每个bean作特殊化的定制。也或者可以把BeanFactory拿到进行缓存,日后使用。

eg:假设有2个业务处理对象,都继承了BeanFactoryHelper,但是具体处理的时候要哪个业务的对象呢?

这个依赖于用户的选择。 你可以注入2个BeanFactoryHelper实例,然后用if --else,但增加一个业务你都需要改代码。

若变动,还要添加代码。如果实现BeanFactoryAware,那么一切都好说,因为Spring实例化之后,只需要根据bean的名称获取对象即可。不会去实例化每一个对象。下面的代码一个片段:

java 复制代码
 public class ControlServiceImpl implements IControlService, BeanFactoryAware {
     private BeanFactory factory;
 
     @Override
     public void setBeanFactory(BeanFactory factory) {
         this.factory = factory;
     }
     @Override
     public OutputObject execute(InputObject inputObject) {
        System.out.println("--------------ControlServiceImpl.execute()方法---------");

        OutputObject outputObject = new OutputObject(ControlConstants.RETURN_CODE.IS_OK);
        try {
            outputObject.setReturnCode(ControlConstants.RETURN_CODE.IS_OK);
            if (inputObject != null) {
                Object object = factory.getBean(inputObject.getService());
                Method mth = object.getClass().getMethod(inputObject.getMethod(), InputObject.class, OutputObject.class);
                mth.invoke(object, inputObject, outputObject);
            } else {
                throw new Exception("InputObject can't be null !!!");
            }
        } catch (Exception e) {
            // 异常处理

        } finally {

        }
        return outputObject;
    }
}
7.ApplicationContextAwareProcessor

o r g . s p r i n g f r a m e w o r k . c o n t e x t . s u p p o r t . A p p l i c a t i o n C o n t e x t A w a r e P r o c e s s o r \textcolor{green}{org.springframework.context.support.ApplicationContextAwareProcessor} org.springframework.context.support.ApplicationContextAwareProcessor

类内部却有6个扩展点可供实现 ,这些类触发的时机在bean实例化之后,初始化之前

该类用于执行各种驱动接口,在bean实例化之后,属性填充之后。所以这里应该来说是有6个扩展点,这里就放一起来说了

  • EnvironmentAware:用于获取EnviromentAware的一个扩展类, 可以获得系统内的所有参数。spring内部也可以通过注入的方式来直接获得。
  • EmbeddedValueResolverAware:用于获取StringValueResolver的一个扩展类, StringValueResolver用于获取基于String类型的properties的变量,都用@Value的方式可以获取,如果实现了这个Aware接口,把StringValueResolver缓存起来,通过这个类去获取String类型的变量,效果是一样的。
  • ResourceLoaderAware:用于获取ResourceLoader的一个扩展类,ResourceLoader可以用于获取classpath内所有的资源对象,可以扩展此类来拿到ResourceLoader对象。
  • ApplicationEventPublisherAware:用于获取ApplicationEventPublisher的一个扩展类,ApplicationEventPublisher可以用来发布事件,结合ApplicationListener来共同使用,下文在介绍ApplicationListener时会详细提到。这个对象也可以通过spring注入的方式来获得。
  • MessageSourceAware:用于获取MessageSource的一个扩展类,MessageSource主要用来做国际化。
  • ApplicationContextAware:用来获取ApplicationContext的一个扩展类,ApplicationContext应该是很多人非常熟悉的一个类了,就是spring上下文管理器,可以手动的获取任何在spring上下文注册的bean,我们经常扩展这个接口来缓存spring上下文,包装成静态方法。同时ApplicationContext也实现了BeanFactoryMessageSourceApplicationEventPublisher等接口,也可以用来做相关接口的事情。
8.BeanNameAware

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . B e a n N a m e A w a r e \textcolor{green}{org.springframework.beans.factory.BeanNameAware} org.springframework.beans.factory.BeanNameAware

触发点:在bean的初始化之前,也就是postProcessBeforeInitialization之前,这个类的触发点方法只有一个:setBeanName

场景:用户可以扩展这个点,在初始化bean之前拿到spring容器中注册的的beanName,来自行修改这个beanName的值(@Component("haha"))。

9.@PostConstruct

在bean的初始化阶段,如果对一个方法标注了@PostConstruct,会先调用这个方法。触发点是在postProcessBeforeInitialization之后,InitializingBean.afterPropertiesSet之前。

使用场景:用户可以对某一方法进行标注,来进行初始化某一个属性 考虑业务

10.InitializingBean

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . I n i t i a l i z i n g B e a n \textcolor{green}{org.springframework.beans.factory.InitializingBean} org.springframework.beans.factory.InitializingBean

为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

触发时机在postProcessAfterInitialization之前。

场景:用户实现此接口,来进行系统启动的时候一些业务指标的初始化工作。

java 复制代码
@Component
public class ExtInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        // 一个 InitializingBean 执行一次
        // spring 初始化方法,作用是在BeanFactory完成属性设置之后,执行自定义的  初始化行为.
        // 执行顺序:在initMethod之前执行,在@PostConstruct之后执行
        System.out.println("InitializingBean");
    }
}

Spring是通过反射来调用init-method指定方法,而实现InitializingBean接口是直接调用afterPropertiesSet方法,所以后者效率高,但使用init-method方式减少了对Spring的依赖

如果调用afterPropertiesSet方法时报错,则不会再调用init-method指定的方法

11.FactoryBean

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . F a c t o r y B e a n \textcolor{green}{org.springframework.beans.factory.FactoryBean} org.springframework.beans.factory.FactoryBean

一般情况下,Spring通过反射机制利用bean的class属性指定支线类去实例化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,可以通过实现该接口定制实例化Bean的逻辑。

FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式

场景:可以扩展这个类,为要实例化的bean作一个代理,比如为该对象的所有的方法作一个拦截,在调用前后输出一行log,

模仿ProxyFactoryBean的功能。

ProxyFactoryBean是创建AOP代理对象的FactoryBean、ProxyFactoryBean的作用就是创建目标对象的代理对象。将对目标对象方法的调用转到对应的代理对象的方法,而且代理对象方法调用前后会执行与之匹配的各个通知器中定义好的方法

ProxyFactoryBean的属性:

  • target:需要被切面增强的对象
  • proxyInterfaces:代理对象所需要实现的接口
  • interceptorsNames:通知器集合(一个Advisor集合)
12.SmartInitializingSingleton

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . S m a r t I n i t i a l i z i n g S i n g l e t o n \textcolor{green}{org.springframework.beans.factory.SmartInitializingSingleton} org.springframework.beans.factory.SmartInitializingSingleton

是spring 4.1中引入的新特效,与InitializingBean的功能类似,都是bean实例化后执行自定义初始化,都是属于spring bean生命周期的增强。但是,SmartInitializingSingleton的定义及触发方式方式上有些区别,它的定义不在当前的bean中。

SmartInitializingSingleton&InitializingBean的区别

(1)SmartInitializingSingleton接口只能作用于非惰性单实例Bean,InitializingBean接口无此要求。

(2)SmartInitializingSingleton接口是在所有非惰性单实例初始化完成之后进行激活回调,InitializingBean接口是在每一个Bean实例初始化完成之后进行激活回调。

这个接口中只有一个方法afterSingletonsInstantiated,其作用是是 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization之后。

场景:用户可以扩展此接口在对所有单例对象初始化完毕后,做一些后置的业务处理。

eg: **spring 容器中 SmartInitializingSingleton 的使用 ** EventListenerMethodProcessor

要用于完成@EventListener注解方式的事件监听。在afterSingletonsInstantiated()方法用于筛选实例中被指定注解修饰的方法。

13.CommandLineRunner

o r g . s p r i n g f r a m e w o r k . b o o t . C o m m a n d L i n e R u n n e r \textcolor{green}{org.springframework.boot.CommandLineRunner} org.springframework.boot.CommandLineRunner

java 复制代码
public interface CommandLineRunner {
    void run(String... var1) throws Exception;
}
//对比
public interface ApplicationRunner {
    void run(ApplicationArguments var1) throws Exception;
}

场景":需要在容器启动的时候执行一些内容,比如:读取配置文件信息,数据库连接,删除临时文件,清除缓存信息,在Spring框架下是通过ApplicationListener监听器来实现的。在Spring Boot中给我们提供了两个接口CommandLineRunner和ApplicationRunner,来帮助我们实现这样的需求

这个接口也只有一个方法:run(String... args),触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner,可以利用@Order来进行排序。

相同点

  • 都可以获取到启动时指定的外部参数。
  • 主逻辑方法名称都是 run 。
  • 在 run 方法内部抛出异常时, 应用都将无法正常启动。

不同点

run 方法的参数不一致, 一个是 String[]数组, 一个是 ApplicationArguments 。

执行顺序

  • 在没有指定加载顺序 @Order 时或 @Order 值一致时, 先执行 ApplicationRunner。
  • 如果指定了加载顺序 @Order,则按照 @Order 的顺序进行执行。

说明:数字越小,优先级越高,也就是@Order(1)注解的类会在@Order(2)注解的类之前执行。

使用场景

应用服务启动时,加载一些数据和执行一些应用的初始化动作。

  • 删除临时文件。
  • 缓存预热:项目启动时热加载数据库数据至缓存。通过相应的服务从获取到数据;将获取到的数据放到缓存中;
  • 清除缓存信息。
  • 读取
14.DisposableBean

o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . D i s p o s a b l e B e a n \textcolor{green}{org.springframework.beans.factory.DisposableBean} org.springframework.beans.factory.DisposableBean

这个扩展点也只有一个方法:destroy(),其触发时机为当此对象销毁时,会自动执行这个方法。比如说运行applicationContext.registerShutdownHook时,就会触发这个方法。

15.ApplicationListener

o r g . s p r i n g f r a m e w o r k . c o n t e x t . A p p l i c a t i o n L i s t e n e r \textcolor{green}{org.springframework.context.ApplicationListener} org.springframework.context.ApplicationListener

准确的说,这个应该不算spring&springboot当中的一个扩展点,ApplicationListener可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。

spring内部也有一些内置事件,这种事件,可以穿插在启动调用中。我们也可以利用这个特性,来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情。

spring事件

  • ApplicationEvent:事件本身 事件接口。
  • ApplicationListener:事件监听者 事件监听器接口,所有的监听器都实现该接口。
  • ApplicationEventPublisher:事件发布者 事件发布接口,ApplicationContext实现了该接口。
  • ApplicationEventMulticaster: Spring事件机制中的事件广播器,执行事件。

执行流程

  • 事件源产生事件,通过事件发布器ApplicationEventPublisher发布事件,

  • 事件广播器ApplicationEventMulticaster会去事件注册表ApplicationContext中找到事件监听器ApplicationListnener,并逐个执行监听器的onApplicationEvent方法,完成事件监听器的逻辑。

    spring主要的内置事件:

  • ContextRefreshedEvent

    ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用 refresh()方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。

  • ContextStartedEvent

    当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。

  • ContextStoppedEvent

    当使用 ConfigurableApplicationContext接口中的 stop()停止ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作

  • ContextClosedEvent

    当使用 ConfigurableApplicationContext接口中的 close()方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启

  • RequestHandledEvent

    这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件

springboot默认启动事件:

  • ApplicationStartingEvent: SpringBoot启动开始的时候执行的事件
  • ApplicationEnvironmentPreparedEvent: SpringBoot对应Enviroment已经准备完毕,但此时上下文context还没有创建。在该监听中获取
  • ConfigurableEnvironment后可以对配置信息做操作,例如:修改默认的配置信息,增加额外的配置信息等等。
  • ApplicationPreparedEvent: SpringBoot上下文context创建完成,但此时Spring中的bean是没有完全加载完成的。在获取完上下文后,可以将上下文传递出去做一些额外的操作。值得注意的是:在该监听器中是无法获取自定义bean并进行操作的。
  • ApplicationReadyEvent: SpringBoot加载完成时候执行的事件。
  • ApplicationFailedEvent: SpringBoot启动异常时执行事件。

合理利用spring提供给我们的扩展点,在spring启动的各个阶段内做一些事情。以达到自定义初始化的目的配置文件信息。

  • 打印日志用于标识服务启动成功或者标识某些属性加载成功。
  • 设置属性值或者启动组件,例如开启某些组件的开关、一些应用级别缓存的加载、启动定时任务等等。
  • 需要使用main方法的入参。
相关推荐
汪子熙1 分钟前
npm install 输出信息解析与最佳实践
javascript·后端
十六点五14 分钟前
JVM(9)——详解Serial垃圾回收器
java·开发语言·jvm·后端
黄雪超18 分钟前
JVM——Synchronized:同步锁的原理及应用
java·开发语言·jvm
Hellyc19 分钟前
Feign进行微服务转发的实现
java·数据库·微服务
晓华-warm20 分钟前
Warm-Flow发布1.7.4, 设计器和流程图优化
java·中间件·流程图·组件·flowable·工作流·activities
Vesper6321 分钟前
【SpringBoot】Spring Boot实现SSE实时推送实战
java·spring boot·后端
用户85126081181724 分钟前
借助 trae 提升效率的真实体验:让文本处理不再繁琐
后端
brzhang26 分钟前
我靠!B站上那些炫酷的数学动画,原来是这个Python库搞定的?!
前端·后端·架构
深栈解码29 分钟前
OpenIM 源码深度解析系列(十七):附录一源码详细项目结构
后端
学习OK呀30 分钟前
MCP 的相关实操学习
人工智能·后端