在这里插入图片描述

一、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:准备刷新上下文环境
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之前已经获取到

<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"/>
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;
}
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 {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("执行MyBeanFactoryPostProcessor01的postProcessBeanFactory方法");//获取工厂当前所有注册的beanNamesString[] 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");}}}}@Overridepublic int getOrder() {return 0;}
}
package com.dd.controller.beanextend;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {@org.junit.Testpublic 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()回调;
  • 在这里插入图片描述
// 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;// 存放普通的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();// 存放BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessorList<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);// BeanDefinitionRegistryPostProcessorregistryProcessors.add(registryProcessor);}else {// 普通BeanFactoryPostProcessorregularPostProcessors.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.// 记录本次要执行的BeanDefinitionRegistryPostProcessorList<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// 配置注册的后置处理器// 1、调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类// 找出所有实现BeanDefinitionRegistryPostProcessor接口的BeanString[] 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、调用所有剩下的BeanDefinitionRegistryPostProcessorsboolean 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//!!!!!!!!!!!!!!!!!!!!!!  huoString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.// 存放实现了PriorityOrdered接口的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();// 存放实现了Ordered接口的BeanFactoryPostProcessorList<String> orderedPostProcessorNames = new ArrayList<>();// 存放其它BeanFactoryPostProcessorList<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接口的BeanFactoryPostProcessorpriorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {// Ordered接口的BeanFactoryPostProcessororderedPostProcessorNames.add(ppName);}else {// 普通BeanFactoryPostProcessornonOrderedPostProcessorNames.add(ppName);}}// 1、调用所有实现PriorityOrdered接口的BeanFactoryPostProcessor// 排序sortPostProcessors(priorityOrderedPostProcessors, beanFactory);// 执行postProcessBeanFactory()回调invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// 2、调用所有实现Ordered接口的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {// 这里会触发BeanFactoryPostProcessor的创建流程orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}// 排序sortPostProcessors(orderedPostProcessors, beanFactory);// 执行postProcessBeanFactory()回调invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// 3、调用所有其他BeanFactoryPostProcessorList<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();
}
// 从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方法来实例化对象;

2. 实例化对象 \textcolor{green}{实例化对象} 实例化对象

  • 进入 doGetBean(),从 getSingleton() 没有找到对象,进入创建 Bean 的逻辑
  • doCreateBean方法创建实例,反射, 只是将对象实例化了,对象内的属性还未设置;
  • 进入 doCreateBean() 后,调用 createBeanInstance()。
  • 进入 createBeanInstance() 后,调用 instantiateBean()。

3. 实例化后置 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初始化就需要从数据库加载到这些配置信息。

//1.定义了一个普通的java类DemoService4,然后通过配置类BeanConfig的@Bean进行注入。
//2.在@Bean注入的时候,指定了初始化方法initMethod
//3.对于@PostConstruct的使用只需要在类的方法上添加注解即可。
//4.对于InitializingBean的使用需要实现接口InitializingBean中的afterPropertiesSet方法。
public class InitDemoService4 implements InitializingBean {@Autowiredprivate Environment environment;public InitDemoService4(){System.out.println("DemoService4的构造方法打印environment="+environment);}/*** 使用JSR-250规范定义的@Postconstruct注解*/@PostConstructpublic 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*/@Overridepublic 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之后执行

@Component
public class ExtInitializingBean implements InitializingBean {@Overridepublic 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注解

@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()

@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应用程序中。例如,根据上下文环境注册属性源或激活概要文件。

@Component
public class P implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 创建一个bean的定义类的对象RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(C.class);// 将Bean 的定义注册到Spring环境registry.registerBeanDefinition("c", rootBeanDefinition);//第一、先调用这个注册cSystem.out.println("postProcessBeanDefinitionRegistry----注册c");}@Overridepublic 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中占位符的处理

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic 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
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {// 1 实例化前置@Overridepublic 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;// 默认什么都不做,返回nullreturn null;}// 3.实例化后置@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {System.out.println("3.postProcessAfterInstantiation被调用了---------beanName:" + beanName);//默认返回true,什么也不做,继续下一步return false;}// 4.属性修改@Overridepublic 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注解的方法会失效*/@Overridepublic 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;}@Overridepublic 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实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

//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

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的名称获取对象即可。不会去实例化每一个对象。下面的代码一个片段:

 public class ControlServiceImpl implements IControlService, BeanFactoryAware {private BeanFactory factory;@Overridepublic void setBeanFactory(BeanFactory factory) {this.factory = factory;}@Overridepublic 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之前。

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

@Component
public class ExtInitializingBean implements InitializingBean {@Overridepublic 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

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方法的入参。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84764.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84764.shtml
英文地址,请注明出处:http://en.pswp.cn/web/84764.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python学习打卡day55

DAY 55 序列预测任务介绍 知识点回顾 序列预测介绍 单步预测多步预测的2种方式 序列数据的处理&#xff1a;滑动窗口多输入多输出任务的思路经典机器学习在序列任务上的劣势&#xff1b;以随机森林为例 作业&#xff1a;手动构造类似的数据集&#xff08;如cosx数据&#xff09…

Leetcode hot100 Java刷题

文章目录 快排146. LRU 缓存acm模式树的前中后序遍历acm模式链表的基本操作1. 两数之和49. 字母异位词分组128. 最长连续序列283. 移动零11. 盛最多水的容器15. 三数之和42. 接雨水53. 最大子数组和56. 合并区间73. 矩阵置零48. 旋转图像141. 环形链表142. 环形链表 II24. 两两…

Linux 命令详解 —— 进程管理

文章目录 精通Linux操作系统(以Centos7为例)进程管理ps常用组合进程状态 STAT 详解高级筛选与格式化输出按条件过滤进程自定义输出字段显示进程树关系排障场景定位高 CPU检查僵尸进程查看进程的线程查看进程打开的文件/网络连接常用组合速查top前5摘要区进程列表信息交互式命令…

【软考高级系统架构论文】论湖仓一体架构及其应用

论文真题&#xff1a; 随着5G、大数据、人工智能、物联网等技术的不断成熟&#xff0c;各行各业的业务场景日益复杂&#xff0c;企业数据呈现出大规模、多样性的特点&#xff0c;特别是非结构化数据呈现出爆发式增长趋势。在这一背景下&#xff0c;企业数据管理不再局限于传统…

Docker 高级管理笔记

前言&#xff1a;Docker 高级管理概述 随着 Docker 技术的广泛应用&#xff0c;容器化已成为现代软件开发与部署的核心方式。本笔记聚焦 Docker 高级管理中的两大关键技术 —— 容器通信与数据持久化&#xff0c;深入解析 Docker 网络模式、端口映射、容器互联机制及数据卷管理…

Spring Boot 项目初始化

一、什么是 CommandLineRunner CommandLineRunner 是 Spring Boot 提供的一个 函数式接口&#xff0c;声明如下&#xff1a; 该接口只有一个 run(String... args) 方法&#xff0c;会在 Spring Boot 容器启动完成后被自动调用。 你可以将它理解为一种“钩子函数”&#xff0c;…

C# winform教程(二)----ComboBox

一、作用 一个可以输入也可以下拉的列表框。 二、属性 一般我们都是使用下拉列表&#xff0c;不使用在线编辑&#xff08;本人没用过&#xff09; 属性 名称内容含义items组合框中项可以定义下拉列表的值DropDownStyle外观和功能是否可以填写&#xff0c;一般选择dropdownli…

FFmpeg裁剪视频在Android上的实现

添加依赖&#xff1a; implementation com.arthenica:mobile-ffmpeg-full:4.4.LTS 代码实现&#xff1a; fun cropMiddleThird(inputPath: String, outputPath: String) {val cmd arrayOf("-y", // 覆盖输出文件"-i", inputPath,"-filter:v&quo…

openEuler 22.03 sp1 更新openssh 10.0p2 —— 筑梦之路

华为欧拉openEuler制作openssh 9.1/9.2/9.3 p1 rpm——筑梦之路_欧拉构建openssh-CSDN博客 上面是需要修改的sshd_config配置&#xff0c;将这3行注释掉。 附上22.03 sp1的yum源文件 # cat openEuler.repo #generic-repos is licensed under the Mulan PSL v2. #You can use t…

AGI(4)大模型的推理综述

本文源自基于基础模型的推理综述《A Survey of Reasoning with Foundation Models》&#xff0c;因为原文有点难于理解&#xff0c;在这个论文的基础上增加了自己的解释和理解&#xff0c;重新整理成此文。大家可以通过查看原文阅读原始论文。 1、推理的概念 推理是解决复杂问题…

Rust 中的宏与函数

在 Rust 编程中&#xff0c;宏&#xff08;Macro&#xff09;和函数&#xff08;Function&#xff09;是两种非常重要的编程工具。虽然它们都可以用来组织代码和实现复用&#xff0c;但它们在定义方式、作用原理、性能、灵活性以及适用场景等方面存在诸多不同。本文将详细介绍 …

c++中左值与右值

在 C++ 中,左值(lvalue) 和 右值(rvalue) 是表达式的基本属性,它们决定了表达式能否被赋值、取地址等操作。 1. 核心定义 左值(lvalue) 特点:表示一个具名的、持久的对象,可位于赋值语句左侧。示例: int x = 42; // x是左值 x = 100; // 合法:左值可…

DeepSeek14-open-webui 常用概念区分

I、“Tools & Functions” 与 Pipelines&#xff08;工作流系统&#xff09;区别 以下是“Tool & Functions”与“Pipelines”的区别、适用场景及作用的详细分析&#xff0c;内容基于参考文档提取与总结&#xff1a; 一、本质区别 维度Tool & FunctionsPipeline…

PaddleOCR + Flask 构建 Web OCR 服务实战

1、前言 随着图像识别技术的发展,OCR(光学字符识别)已经成为很多应用场景中的基础能力。PaddleOCR 是百度开源的一个高性能 OCR 工具库,支持中英文、多语言、轻量级部署等特性。 而 Flask 是一个轻量级的 Python Web 框架,非常适合快速构建 RESTful API 或小型 Web 应用…

C++结构体初始化与成员函数实现语法详解

C结构体初始化与成员函数实现语法详解 一、结构体静态成员初始化语法 在C中&#xff0c;静态成员变量需要在类外部进行定义和初始化。提供的代码展示了如何为MAIN_PROPULSION_CAN类的静态成员变量进行初始化&#xff1a; MAIN_PROPULSION_CAN::VoltageThresholds MAIN_PROPU…

买了新内存条插上bios识别,进入系统不可用,b450主板,内存插槽A1A2 可以点亮,B1B2不可以,A2B2不可以,B1B2还是不可以

提示&#xff1a;买了新内存条插上bios识别&#xff0c;进入系统不可用&#xff0c;b450主板&#xff0c;内存插槽A1A2 可以点亮&#xff0c;B1B2不可以&#xff0c;A2B2不可以 文章目录 前言——环境一、第一种情况&#xff0c;开机不能点亮二、第二种情况, 总内存&#xff0c…

7.4.1_2B树的插入删除

B树插入&#xff1a; 假如是m阶B树&#xff0c;插入关键字时都要满足每个节点上的关键字个数最少为m/2向上取整-1关键字&#xff0c;最多有m-1个关键字&#xff0c;且每次插入的新元素一定是放在最底层的终端节点(因为如果不是放在终端节点&#xff0c;会导致该节点上可能有叶子…

Linux系统基本操作指令

Linux系统基本操作指令 文章目录 Linux系统基本操作指令一、介绍二、基础设置2.1 设置ubuntu与window的共享目录2.2 ubuntu系统简单介绍 三、Linux命令及工具介绍3.1 目录管理命令(功能&#xff0c;格式&#xff0c;参数&#xff0c;系统参数)3.2 文件操作命令 四、网络命令4.1…

系统思考VS心智模式

在这张图片中&#xff0c;我们看到的是两杯相同价格的咖啡&#xff0c;它们的价格显示方式不同。一杯咖啡的原价和现价都写得很大&#xff0c;而另一杯的价格则以较小的字体呈现。这种微妙的设计差异揭示了一个有趣的心理现象——心智模式。 人们在面对同样的价格时&#xff0…

all()函数和any()函数

参考文献 在if上使用.all和.any # 中心点未改变&#xff0c;说明达到稳态&#xff0c;结束递归if (self.points new_center).all():sum self.__sumdis(result)return result, self.points, sum