二、Spring的执行流程

文章目录

  • 1. spring的初始化过程
    • 1.1 ClassPathXmlApplicationContext的构造方法
    • 1.2 refresh方法(核心流程)
      • 1.2.1 prepareRefresh() 方法
      • 1.2.2 obtainFreshBeanFactory() 方法
      • 1.2.3 prepareBeanFactory() 方法
      • 1.2.4 invokeBeanFactoryPostProcessors() 方法
      • 1.2.5 registerListeners() 方法
  • 2. spring创建Bean过程
  • 3. finishRefresh() 详解

1. spring的初始化过程

1.1 ClassPathXmlApplicationContext的构造方法

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {super(parent); // 初始化资源文件this.setConfigLocations(configLocations);  // 用来设置配置文件路径的if (refresh) {this.refresh(); // 核心流程}}

1.2 refresh方法(核心流程)

public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {// 见 1.2.1// step 1:作一些基本的准备工作(初始化IOC容器 即:ClassPathXmlApplicationContext 的一些状态值、获取系统环境值等)this.prepareRefresh();// 见 1.2.2// step 2:创建 BeanFactory 对象(实际是:DefaultListableBeanFactory)// 加载xml配置文件或注解的bean信息到当前工厂,最重要的就是 BeanDefinition// 创建过程中会创建 BeanDefinition,它保存由配置文件 或 注解标注的 bean 信息ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();// 见 1.2.3// step 3:设置 BeanFactory 的类加载器,添加spring默认的 BeanPostProcessor,手动注册几个特殊的 beanthis.prepareBeanFactory(beanFactory);try {// step4:(模板方法)这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化// 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事this.postProcessBeanFactory(beanFactory);// 见 1.2.4// step5:调用所有 BeanFactoryPostProcessor(在当前IOC容器中保存) 中的方法this.invokeBeanFactoryPostProcessors(beanFactory);// step6:在实例化 Bean 之前,作准备// 在实例化 Bean 之前保存(注册) BeanPostProcessorsthis.registerBeanPostProcessors(beanFactory);// step 7:国际化this.initMessageSource();// step 8:初始化当前 ApplicationContext 的事件广播器this.initApplicationEventMulticaster();// step 9:从方法名就可以知道,典型的模板方法(钩子方法),      // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)// 模板方法--springboot实现了这个方法this.onRefresh();// 见 1.2.5 // step 10:注册事件监听器,监听器需要实现 ApplicationListener 接口this.registerListeners();// 见 2// step 11:初始化所有的 singleton beans(lazy-init 的除外)this.finishBeanFactoryInitialization(beanFactory);// step 12:最后,广播事件,ApplicationContext 初始化完成this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

1.2.1 prepareRefresh() 方法

protected void prepareRefresh() {// 初始化标志值this.startupDate = System.currentTimeMillis();this.closed.set(false);this.active.set(true);// 日志相关if (this.logger.isDebugEnabled()) {if (this.logger.isTraceEnabled()) {this.logger.trace("Refreshing " + this);} else {this.logger.debug("Refreshing " + this.getDisplayName());}}// 初始化参数资源(此方法默认为空方法可继承并扩展)this.initPropertySources();// 获取系统环境的相关参数并进行验证 ※this.getEnvironment().validateRequiredProperties();// 创建了监听器的集合 ※if (this.earlyApplicationListeners == null) {this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);} else {this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// 创建了监听时间的集合 ※this.earlyApplicationEvents = new LinkedHashSet();}

1.2.2 obtainFreshBeanFactory() 方法

// 可定位至 AbstractRefreshableApplicationContext 中的 refreshBeanFactory  方法
protected final void refreshBeanFactory() throws BeansException {if (this.hasBeanFactory()) {this.destroyBeans();this.closeBeanFactory();}try {// 创建 DefaultListableBeanFactory  的实例作为 BeanFactoryDefaultListableBeanFactory beanFactory = this.createBeanFactory();// 设置 序列化IDbeanFactory.setSerializationId(this.getId());// 设置属性值this.customizeBeanFactory(beanFactory);// 将xml文件 或 注解标注的 bean 保存为 BeanDefinition,并由BeanFactory同一管理(Map存储)this.loadBeanDefinitions(beanFactory);synchronized(this.beanFactoryMonitor) {this.beanFactory = beanFactory;}} catch (IOException var5) {throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);}}

1.2.3 prepareBeanFactory() 方法

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.//设置上下文环境的启动类加载器beanFactory.setBeanClassLoader(getClassLoader());//添加bean表达式解释器,为了能够让我们的beanFactory去解析bean表达式beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//spring内部的属性编辑器、既读取配置文件beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.//添加BeanPostProcessorbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//跳过以下6个属性的自动注入//因为在ApplicationContextAwareProcessor后置处理器中通过setter注入beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.注册四个特殊的bean//在应用代码就可以通过类型自动装配把工厂实例和ApplicationContext实例设置到自定义bean的属性中//这四个属性都会被自动设置,虽然没有在显示的在bean定义xml中注入它们beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Register early post-processor for detecting inner beans as ApplicationListeners.//注册事件监听器beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// Register default environment beans.// 如果没有定义 "environment" 这个 bean,那么 Spring 会 "手动" 注册一个if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}// 如果没有定义 "systemProperties" 这个 bean,那么 Spring 会 "手动" 注册一个if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}// 如果没有定义 "systemEnvironment" 这个 bean,那么 Spring 会 "手动" 注册一个if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}
}

1.2.4 invokeBeanFactoryPostProcessors() 方法

  • 方法虽长大概总结一下就是,判断beanFactory类型,然后将注册的BeanPostFactory放入、排好顺序、执行。
  • invokeBeanFactoryPostProcessors 方法的内容其实比较少,大部分过程在注释都已经写清楚,这边在稍微总结一下。
  • 整个 invokeBeanFactoryPostProcessors 方法围绕两个接口,BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor,其中 BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor
  • BeanDefinitionRegistryPostProcessor 主要用来在常规 BeanFactoryPostProcessor 检测开始之前注册其他 Bean 定义,说的简单点,就是 BeanDefinitionRegistryPostProcessor 具有更高的优先级,执行顺序在 BeanFactoryPostProcessor 之前
    public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();// 1.判断beanFactory是否为BeanDefinitionRegistry,beanFactory为DefaultListableBeanFactory,// 而DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,因此这边为trueif (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 用于存放普通的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();// 用于存放BeanDefinitionRegistryPostProcessorList<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();// 2.首先处理入参中的beanFactoryPostProcessors// 遍历所有的beanFactoryPostProcessors, 将BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor区分开for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {// 2.1 如果是BeanDefinitionRegistryPostProcessorBeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;// 2.1.1 直接执行BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法registryProcessor.postProcessBeanDefinitionRegistry(registry);// 2.1.2 添加到registryProcessors(用于最后执行postProcessBeanFactory方法)registryProcessors.add(registryProcessor);}else {// 2.2 否则,只是普通的BeanFactoryPostProcessor// 2.2.1 添加到regularPostProcessors(用于最后执行postProcessBeanFactory方法)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.// 用于保存本次要执行的BeanDefinitionRegistryPostProcessorList<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.// 3.调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类// 3.1 找出所有实现BeanDefinitionRegistryPostProcessor接口的Bean的beanNameString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// 3.2 遍历postProcessorNamesfor (String ppName : postProcessorNames) {// 3.3 校验是否实现了PriorityOrdered接口if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {// 3.4 获取ppName对应的bean实例, 添加到currentRegistryProcessors中,currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));// 3.5 将要被执行的加入processedBeans,避免后续重复执行processedBeans.add(ppName);}}// 3.6 进行排序(根据是否实现PriorityOrdered、Ordered接口和order值来排序)sortPostProcessors(currentRegistryProcessors, beanFactory);// 3.7 添加到registryProcessors(用于最后执行postProcessBeanFactory方法)registryProcessors.addAll(currentRegistryProcessors);// 3.8 遍历currentRegistryProcessors, 执行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);// 3.9 执行完毕后, 清空currentRegistryProcessorscurrentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.// 4.调用所有实现了Ordered接口的BeanDefinitionRegistryPostProcessor实现类(过程跟上面的步骤3基本一样)// 4.1 找出所有实现BeanDefinitionRegistryPostProcessor接口的类, 这边重复查找是因为执行完上面的BeanDefinitionRegistryPostProcessor,// 可能会新增了其他的BeanDefinitionRegistryPostProcessor, 因此需要重新查找postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {// 校验是否实现了Ordered接口,并且还未执行过if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);// 4.2 遍历currentRegistryProcessors, 执行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.// 5.最后, 调用所有剩下的BeanDefinitionRegistryPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;// 5.1 找出所有实现BeanDefinitionRegistryPostProcessor接口的类postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {// 5.2 跳过已经执行过的if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);// 5.3 如果有BeanDefinitionRegistryPostProcessor被执行, 则有可能会产生新的BeanDefinitionRegistryPostProcessor,// 因此这边将reiterate赋值为true, 代表需要再循环查找一次reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);// 5.4 遍历currentRegistryProcessors, 执行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.// 6.调用所有BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法(BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor)invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);// 7.最后, 调用入参beanFactoryPostProcessors中的普通BeanFactoryPostProcessor的postProcessBeanFactory方法invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.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!// 到这里 , 入参beanFactoryPostProcessors和容器中的所有BeanDefinitionRegistryPostProcessor已经全部处理完毕,// 下面开始处理容器中的所有BeanFactoryPostProcessor// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// 8.找出所有实现BeanFactoryPostProcessor接口的类String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.// 用于存放实现了PriorityOrdered接口的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();// 用于存放实现了Ordered接口的BeanFactoryPostProcessor的beanNameList<String> orderedPostProcessorNames = new ArrayList<>();// 用于存放普通BeanFactoryPostProcessor的beanNameList<String> nonOrderedPostProcessorNames = new ArrayList<>();// 8.1 遍历postProcessorNames, 将BeanFactoryPostProcessor按实现PriorityOrdered、实现Ordered接口、普通三种区分开for (String ppName : postProcessorNames) {// 8.2 跳过已经执行过的if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {// 8.3 添加实现了PriorityOrdered接口的BeanFactoryPostProcessorpriorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {// 8.4 添加实现了Ordered接口的BeanFactoryPostProcessor的beanNameorderedPostProcessorNames.add(ppName);}else {// 8.5 添加剩下的普通BeanFactoryPostProcessor的beanNamenonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.// 9.调用所有实现PriorityOrdered接口的BeanFactoryPostProcessor// 9.1 对priorityOrderedPostProcessors排序sortPostProcessors(priorityOrderedPostProcessors, beanFactory);// 9.2 遍历priorityOrderedPostProcessors, 执行postProcessBeanFactory方法invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.// 10.调用所有实现Ordered接口的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {// 10.1 获取postProcessorName对应的bean实例, 添加到orderedPostProcessors, 准备执行orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}// 10.2 对orderedPostProcessors排序sortPostProcessors(orderedPostProcessors, beanFactory);// 10.3 遍历orderedPostProcessors, 执行postProcessBeanFactory方法invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.// 11.调用所有剩下的BeanFactoryPostProcessorList<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {// 11.1 获取postProcessorName对应的bean实例, 添加到nonOrderedPostProcessors, 准备执行nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}// 11.2 遍历nonOrderedPostProcessors, 执行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...// 12.清除元数据缓存(mergedBeanDefinitions、allBeanNamesByType、singletonBeanNamesByType),// 因为后处理器可能已经修改了原始元数据,例如, 替换值中的占位符...beanFactory.clearMetadataCache();}

1.2.5 registerListeners() 方法

引用自:https://blog.csdn.net/weixin_44643680/article/details/123331389?spm=1001.2014.3001.5502

protected void registerListeners() {// Register statically specified listeners first.// 首先注册静态的指定的监听器,注册的是特殊的事件监听器,而不是配置中的beanfor (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!// 这里不会初始化FactoryBean,我们需要保留所有的普通bean// 不会实例化这些bean,让后置处理器可以感知到它们String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// Publish early application events now that we finally have a multicaster...// 现在有了事件广播组,发布之前的应用事件Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}

这个方法要做的很简单,就是两个循环遍历,把Spring通过硬编码定义的监听器注册到容器中,然后把我们自定义的监听器注册到容器中,通过这些直接叙述有一些苍白无力,我们写一个简单的发布-订阅的例子方便理解。
在发布订阅模式用需要四个角色:
ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。抽象类。
ApplicationListener:事件监听器,用于接收事件处理时间。接口。
ApplicationEventMulticaster:事件管理者,可以注册(添加)/移除/发布事件。用于事件监听器的注册和事件的广播。接口。
ApplicationEventPublisher:事件发布者,委托事件管理者ApplicationEventMulticaster完成事件发布。
在这里插入图片描述

事件:

@Component
public class MyEvent extends ApplicationEvent {private static final long serialVersionUID = 1L;/*** Create a new ApplicationEvent.** @param source the object on which the event initially occurred (never {@code null})*/public MyEvent(Object source) {super(source);}
}

事件监听器:

@Component
public class MyEventListener implements ApplicationListener<MyEvent> {@EventListener //@EventListener注解实现事件监听@Overridepublic void onApplicationEvent(MyEvent event) {Object msg = event.getSource();System.out.println("自定义事件监听器(MyEventListener1)收到发布的消息: " + msg);}
}

事件发布者:

public static void main(String[] args) {System.out.println(1);ApplicationContext ac =new AnnotationConfigApplicationContext(MyEventListener.class);MyEvent myEvent=new MyEvent(new Object());ac.publishEvent(myEvent);}

那么事件的管理器跑哪去了呢?
我们在 registerListeners()方法上面打一个断点,看看我们自定义的事件是如何在Spring中起作用的。
在这里插入图片描述

第一个循环是Spring默认的监听器默认情况下是空。

我们自定义的事件监听器在第二个循环里面被加载到了ApplicationEventMulticaster中,已经很明显了,ApplicationEventMulticaster就是我们的事件管理者。

我们在把他们之间的关系详细串一下
在这里插入图片描述

注:广播器和上面的管理者是一个意思
到这个阶段,事件管理者和监听器都在Spring容器里初始化和注册了,之后就可以实现监听者模式了,对事件的发布进行监听然后处理。
在就是ac.publishEvent(myEvent);方法发布事件后进行的业务处理。

ApplicationContext ac =new AnnotationConfigApplicationContext(MyEventListener.class);MyEvent myEvent=new MyEvent(new Object());ac.publishEvent(myEvent);

事件监听机制实际就是主题-订阅模式(观察者模式)的实现,能够降低代码耦合。
本文顺便把观察者模式简要的叙述一下,方便读者可以更好的理解。
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

public class RMBrateTest {public static void main(String[] args) {Rate rate = new RMBrate();Company watcher1 = new ImportCompany();Company watcher2 = new ExportCompany();rate.add(watcher1);rate.add(watcher2);rate.change(10);rate.change(-9);}
}
//抽象目标:汇率
abstract class Rate {protected List<Company> companys = new ArrayList<Company>();//增加观察者方法public void add(Company company) {companys.add(company);}//删除观察者方法public void remove(Company company) {companys.remove(company);}public abstract void change(int number);
}
//具体目标:人民币汇率
class RMBrate extends Rate {public void change(int number) {for (Company obs : companys) {((Company) obs).response(number);}}
}
//抽象观察者:公司
interface Company {void response(int number);
}
//具体观察者1:进口公司
class ImportCompany implements Company {public void response(int number) {if (number > 0) {System.out.println("人民币汇率升值" + number + "个基点,降低了进口产品成本,提升了进口公司利润率。");} else if (number < 0) {System.out.println("人民币汇率贬值" + (-number) + "个基点,提升了进口产品成本,降低了进口公司利润率。");}}
}
//具体观察者2:出口公司
class ExportCompany implements Company {public void response(int number) {if (number > 0) {System.out.println("人民币汇率升值" + number + "个基点,降低了出口产品收入,降低了出口公司的销售利润率。");} else if (number < 0) {System.out.println("人民币汇率贬值" + (-number) + "个基点,提升了出口产品收入,提升了出口公司的销售利润率。");}}
}

汇率变化就是一个事件,当该事件发生时,它的观察者出口公司和进口公司就要做相应的变化。

书归正传重新回到registerListeners()方法中,这时所有的监听器都注册到了容器中,只等publishEvent()发布事件以后,就会执行我们监听器中的业务逻辑。

据说在Springboot中应用了大量的发布订阅模式,抱着求知若渴的态度我们去Springboot中搂一眼,在registerListeners()上面打一个断点,看看和Spring上面的断点有什么区别。
在这里插入图片描述

在Spirng中监听器默认是空,当时在Springboot中有15个之多,不愧是加强版的Spring。具体这些监听器是干嘛的我们就不深究了,在Springboot中会对其逐步拆解的。

2. spring创建Bean过程

引用自:https://blog.csdn.net/weixin_44643680/article/details/123372301?spm=1001.2014.3001.5502

  • 今天解读Spring核心方法refresh()中最最重要的一个方法 finishBeanFactoryInitialization() 方法,该方法负责初始化所有的单例bean

  • 到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environmentsystemProperties

  • 剩下的就是初始化 singleton beans 了,大都数我们的业务中都是单例bean,就像我们写的@Controller@Service的类(没有设置懒加载的)都是在这个地方初始化,以供我们使用,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans

  • 我们深入finishBeanFactoryInitialization(beanFactory)中,里面的调用线路错综复杂,还望读者可以做好心理准备。

/*** 负责单例bean的初始化* Finish the initialization of this context's bean factory,* initializing all remaining singleton beans.*/protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.//最先初始化名字为 conversionService的类,conversionService类 它用来将前端传过来的参数和后端的 controller 方法上的参数进行绑定的时候用//尤其是用于非基础类型的转换if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(//初始化在getBean()方法中实现beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Register a default embedded value resolver if no bean post-processor// (such as a PropertyPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.// 先初始化 LoadTimeWeaverAware 类型的 Bean aop相关注:大概有个印象,以后解析aop会和它串起来。String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.//freeze的单词意思是冻结,这个时候已经开始预初始化, bean 定义解析、加载、注册先停止beanFactory.freezeConfiguration();// Instantiate all remaining (non-lazy-init) singletons.//开始初始化beanFactory.preInstantiateSingletons();}

该方法是判断bean的一系列是不是属于某个类型的bean,如果是就调用 getBean() 方法,如果不是,就调用beanFactory.preInstantiateSingletons()进行初始化,我们先把 getBean()放一放,重点看一看 beanFactory.preInstantiateSingletons() 方法。

@Overridepublic void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.// this.beanDefinitionNames 保存了所有的 beanNamesList<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...下面这个循环,触发所有的非懒加载的 singleton beans 的初始化操作for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 非抽象、非懒加载的 singletons。如果配置了 'abstract = true',那是不需要初始化的if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {// 处理 FactoryBean (负责初始化工厂的bean)if (isFactoryBean(beanName)) {// FactoryBean 的话,在 beanName 前面加上 ‘&’ 符号//此处调用getBean()方法Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;// 判断当前 FactoryBean 是否是 SmartFactoryBean 的实现boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {// 对于普通的 Bean,只要调用 getBean(beanName) 这个方法就可以进行初始化了getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...// 到这里说明所有的非懒加载的 singleton beans 已经完成了初始化// 如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的,那么在这里得到回调//如果你想在单例bean初始化后做一些事 那就实现该接口for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}}
  • preInstantiateSingletons() 方法的主要任务是进行初始化的,在初始化前同样是一系列判断,如,是否是懒加载的,是否是一个factorybean(一个特别的bean,负责工厂创建的bean),最后调用 getBean() 方法。
    其中有个插曲是否实现了SmartInitializingSingleton接口,将接口让你可以在bean初始化后做一些事,我们写一个简单的实例测试一下
    在这里插入图片描述

  • 其他地方读者看注释了解一下即可,我们开始继续深入getBean()方法

  • getBean()方法内部调用了doGetBean()我们直接看doGetBean方法

    // 我们在剖析初始化 Bean 的过程,但是 getBean 方法我们经常是用来从容器中获取 Bean 用的,注意切换思路,// 已经初始化过了就从容器中直接返回,否则就先初始化再返回protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// 获取一个 “正统的” beanName,处理两种情况,一个是前面说的 FactoryBean(前面带 ‘&’),// 一个是别名问题,因为这个方法是 getBean,获取 Bean 用的,你要是传一个别名进来,是完全可以的String beanName = transformedBeanName(name);// 返回值Object bean;// Eagerly check singleton cache for manually registered singletons.// 检查下是不是已经创建过了Object sharedInstance = getSingleton(beanName);// 这里说下 args ,虽然看上去一点不重要。前面我们一路进来的时候都是 getBean(beanName),// 所以 args 传参其实是 null 的,但是如果 args 不为空的时候,那么意味着调用方不是希望获取 Bean,而是创建 Beanif (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}// 下面这个方法:如果是普通 Bean 的话,直接返回 sharedInstance,// 如果是 FactoryBean 的话,返回它创建的那个实例对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.// 创建过了此 beanName 的 prototype 类型的 bean,那么抛异常,// 往往是因为陷入了循环引用 哦,原来之前的循环依赖都是在这抛的异常,再有问题就不是无头苍蝇了if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.// 检查一下这个 BeanDefinition 在容器中是否存在 BeanDefinition既是包含了bean的一系列信息BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.// 如果当前容器不存在这个 BeanDefinition,试试父容器中有没有String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {// Delegation to parent with explicit args.// 返回父容器的查询结果return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType != null) {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}else {return (T) parentBeanFactory.getBean(nameToLookup);}}if (!typeCheckOnly) {// typeCheckOnly 为 false,将当前 beanName 放入一个 alreadyCreated 的 Set 集合中。markBeanAsCreated(beanName);}/** 稍稍总结一下:* 到这里的话,要准备创建 Bean 了,对于 singleton 的 Bean 来说,容器中还没创建过此 Bean;* 对于 prototype 的 Bean 来说,本来就是要创建一个新的 Bean。*/try {RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.// 先初始化依赖的所有 Bean,这个很好理解。// 注意,这里的依赖指的是 depends-on 中定义的依赖String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {// 检查是不是有循环依赖,这里的循环依赖和我们前面说的循环依赖又不一样if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 注册一下依赖关系registerDependentBean(dep, beanName);try {// 先初始化被依赖项getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// Create bean instance.// 如果是 singleton scope 的,创建 singleton 的实例if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// 执行创建 Bean,详情继续深入// 第三个参数 args 数组代表创建实例需要的参数,不就是给构造方法用的参数,或者是工厂 Bean 的参数嘛,不过要注意,在我们的初始化阶段,args 是 null。// 这回我们要到一个新的类了 AbstractAutowireCapableBeanFactory,看类名,AutowireCapable?类名是不是也说明了点问题了。// 主要是为了以下场景,采用 @Autowired 注解注入属性值:return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}// 如果是 prototype scope 的,创建 prototype 的实例else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);// 执行创建 BeanprototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");}Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.// 最后,检查一下类型对不对,不对的话就抛异常,对的话就返回了if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;}

具体的实例化过程在createBean()方法中,我们继续深入createBean()方法。

@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.// 确保 BeanDefinition 中的 Class 被加载Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.// 准备方法覆写,这里又涉及到一个概念:MethodOverrides,它来自于 bean 定义中的 <lookup-method />// 和 <replaced-method />,如果读者感兴趣,回到 bean 解析的地方看看对这两个标签的解析。try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.// 让 InstantiationAwareBeanPostProcessor 在这一步有机会返回代理,// 在 《Spring AOP 源码分析》那篇文章中有解释,这里先跳过Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {// 重头戏,创建 beanObject beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

我们继续往里看 doCreateBean 这个方法,这个调用过程是真的深

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 说明不是 FactoryBean,这里实例化 Bean,这里非常关键,细节之后再说**********instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.// 下面这块代码是为了解决循环依赖的问题,这是个重头戏,解决循环依赖问题boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值***************populateBean(beanName, mbd, instanceWrapper);// 还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口?// 这里就是处理 bean 初始化完成后的各种回调**************exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}// 下面这块代码是为了解决循环依赖的问题,这是个重头戏,解决循环依赖问题    if (earlySingletonExposure) {//循环依赖的核心方法调用Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

到这里,我们已经分析完了 doCreateBean 方法,总的来说,我们已经说完了整个初始化流程。
在实例化bean后有一个特别重要的知识点,也是面试中最常问的,Spring怎么解决循环依赖问题?核心代码就在这个方法里面。
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。
如下图
在这里插入图片描述

doCreateBean 方法有三个核心流程。
在这里插入图片描述

(1)createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
(2)populateBean:填充属性,这一步主要是多bean的依赖属性进行填充
(3)initializeBean:调用spring xml中的init 方法。
从上面讲述的单例bean初始化步骤我们可以知道,循环依赖主要发生在第一、第二步。也就是构造器循环依赖和field循环依赖。
那么我们要解决循环引用也应该从初始化过程着手,对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。
我们看一下getSingleton方法。
该方法还依赖于三个map,这三个map就是三级缓存

/** Cache of singleton objects: bean name to bean instance. */
//单例对象的cache
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. */
// 单例对象工厂的cache
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. */
//提前曝光的单例对象的Cache
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);//判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象// 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);// 是否允许从singletonFactories中通过getObject拿到对象if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}

分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。
如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取(三级缓存仅保存的是bean的普通对象,不是AOP后代理对象),如果获取到了则:

this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);
  • 从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存(如果需要AOP会提前进行AOP操作)(在二级缓存中若保存的是AOP后的的代理对象,则会被原始bean周期中的AOP操作与放入单例池的操作时进行判断)
  • 从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。这就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。
  • A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中
  • 此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。
  • 知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
  • 接下来我们挑 doCreateBean 中的三个细节出来说说。一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。
    这三个方法也是极其复杂的,读者有兴趣可以继续的深入进去。
    1、 createBeanInstance 方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.// 确保已经加载了此 classClass<?> beanClass = resolveBeanClass(mbd, beanName);// 校验一下这个类的访问权限if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());}Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() != null) {// 采用工厂方法实例化,不熟悉这个概念的读者请看附录,注意,不是 FactoryBeanreturn instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...// 如果不是第一次创建,比如第二次创建 prototype bean。// 这种情况下,我们可以从第一次创建知道,采用无参构造函数,还是构造函数依赖注入 来完成实例化boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {// 构造函数依赖注入return autowireConstructor(beanName, mbd, null, null);}else {// 无参构造函数return instantiateBean(beanName, mbd);}}// Candidate constructors for autowiring?// 判断是否采用有参构造函数Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {// 构造函数依赖注入return autowireConstructor(beanName, mbd, ctors, args);}// Preferred constructors for default construction?ctors = mbd.getPreferredConstructors();if (ctors != null) {// 构造函数依赖注入return autowireConstructor(beanName, mbd, ctors, null);}// No special handling: simply use no-arg constructor.// 调用无参构造函数return instantiateBean(beanName, mbd);}

看一下instantiateBean方法是怎么做的。

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {try {Object beanInstance;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),getAccessControlContext());}else {// 实例化beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);}// 包装一下,返回BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);}}

我们可以看到,关键的地方在于:beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 里面是具体是实例化过程,我们进去看看。

@Overridepublic Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// Don't override the class with CGLIB if no overrides.// 如果不存在方法覆写,那就使用 java 反射进行实例化,否则使用 CGLIB,// 方法覆写 请参见附录"方法注入"中对 lookup-method 和 replaced-method 的介绍if (!bd.hasMethodOverrides()) {Constructor<?> constructorToUse;synchronized (bd.constructorArgumentLock) {constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse == null) {final Class<?> clazz = bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, "Specified class is an interface");}try {if (System.getSecurityManager() != null) {constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);}else {constructorToUse = clazz.getDeclaredConstructor();}bd.resolvedConstructorOrFactoryMethod = constructorToUse;}catch (Throwable ex) {throw new BeanInstantiationException(clazz, "No default constructor found", ex);}}}// 利用构造方法进行实例化return BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass.// 存在方法覆写,利用 CGLIB 来完成实例化,需要依赖于 CGLIB 生成子类,这里就不展开了。// tips: 因为如果不使用 CGLIB 的话,存在 override 的情况 JDK 并没有提供相应的实例化支持return instantiateWithMethodInjection(bd, beanName, owner);}}

到这里,我们就算实例化完成了。我们开始说怎么进行属性注入。
2、populateBean 方法

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {if (bw == null) {if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}else {// Skip property population phase for null instance.return;}}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}}// bean 实例的所有属性都在这里了PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);int resolvedAutowireMode = mbd.getResolvedAutowireMode();// 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}// 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor// 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs != null) {// 设置 bean 实例的属性值applyPropertyValues(beanName, mbd, bw, pvs);}}

属性注入完成后,这一步其实就是处理各种回调了,这块代码比较简单。
3、 initializeBean方法

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// BeanPostProcessor 的 postProcessBeforeInitialization 回调wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 处理 bean 中定义的 init-method,// 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// BeanPostProcessor 的 postProcessAfterInitialization 回调//BeanPostProcessor 的两个回调都发生在这边,只不过中间处理了 init-methodwrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

自此,Spring实例化单例非懒加载bean的过程也就完成了,这也是Spirng最最重要的方法了。在我们的日常使用Spring中,定义好各个类,然后在上面加上,@Controller,@Service,Autowired等注解,这些注解是怎么起作用的呢?

3. finishRefresh() 详解

引用自:https://blog.csdn.net/weixin_44643680/article/details/123429092?spm=1001.2014.3001.5502
Spring IoC 的核心内容要收尾了,本文将对最后一个方法 finishRefresh 进行介绍,位于refresh 方法中的第九个位置。
本章实际是对发布订阅模式的一种补充,这是Spring在刷新事件完成后发布事件。
由于存在上下文关系,本文也会对 initApplicationEventMulticaster 方法、registerListeners 方法进行回顾。 我们回到refresh 方法中

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.//1、刷新前的准备prepareRefresh();// Tell the subclass to refresh the internal bean factory.//2、将会初始化 BeanFactory、加载 Bean、注册 BeanConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.//3、设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 beanprepareBeanFactory(beanFactory);try {//4、模板方法// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.//执行BeanFactory后置处理器invokeBeanFactoryPostProcessors(beanFactory);// 5、Register bean processors that intercept bean creation.//注册bean后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.//国际化initMessageSource();// Initialize event multicaster for this context.//初始化事件广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.//6、模板方法--springboot实现了这个方法onRefresh();// Check for listener beans and register them.//7、注册监听器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//8、完成bean工厂的初始化**方法重要**********************************************finishBeanFactoryInitialization(beanFactory);//9、 Last step: publish corresponding event.//完成上下文的刷新工作finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

我们首先知道这个三个方法的作用:
initApplicationEventMulticaster():初始化应用的事件广播器

/*** Initialize the ApplicationEventMulticaster.* Uses SimpleApplicationEventMulticaster if none defined in the context.* @see org.springframework.context.event.SimpleApplicationEventMulticaster*/protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 1.判断BeanFactory是否已经存在事件广播器(固定使用beanName=applicationEventMulticaster)if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {// 1.1 如果已经存在,则将该bean赋值给applicationEventMulticasterthis.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isTraceEnabled()) {logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {// 1.2 如果不存在,则使用SimpleApplicationEventMulticasterthis.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isTraceEnabled()) {logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}}

最终只做了一件事,初始化应用的事件广播器。(具体什么是事件广播器及其作用可见上上篇文章,具体就不在吃赘述了)
registerListeners():注册监听器。见上上篇文章
finishRefresh():完成上下文的刷新工作,本文重点。 首先概览finishRefresh方法

    protected void finishRefresh() {// Clear context-level resource caches (such as ASM metadata from scanning).//清除资源缓存clearResourceCaches();// Initialize lifecycle processor for this context.// // 1.为此上下文初始化生命周期处理器initLifecycleProcessor();// Propagate refresh to lifecycle processor first.// 2.首先将刷新完毕事件传播到生命周期处理器(触发isAutoStartup方法返回true的SmartLifecycle的start方法)getLifecycleProcessor().onRefresh();// Publish the final event.// 3.推送上下文刷新完毕事件到相应的监听器publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);}

1、2、3是重点内容
1.为此上下文初始化生命周期处理器

    protected void initLifecycleProcessor() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 1.判断BeanFactory是否已经存在生命周期处理器(固定使用beanName=lifecycleProcessor)if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {this.lifecycleProcessor =beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);if (logger.isTraceEnabled()) {logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");}}else {// 1.2 如果不存在,则使用DefaultLifecycleProcessorDefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();defaultProcessor.setBeanFactory(beanFactory);this.lifecycleProcessor = defaultProcessor;// 并将DefaultLifecycleProcessor作为默认的生命周期处理器,注册到BeanFactory中beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);if (logger.isTraceEnabled()) {logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");}}}

2.首先将刷新完毕事件传播到生命周期处理器

private void startBeans(boolean autoStartupOnly) {// 1.获取所有的Lifecycle beanMap<String, Lifecycle> lifecycleBeans = getLifecycleBeans();// 将Lifecycle bean 按阶段分组,阶段通过实现Phased接口得到Map<Integer, LifecycleGroup> phases = new HashMap<>();// 2.遍历所有Lifecycle bean,按阶段值分组lifecycleBeans.forEach((beanName, bean) -> {// autoStartupOnly=true代表是ApplicationContext刷新时容器自动启动;autoStartupOnly=false代表是通过显示的调用启动// 3.当autoStartupOnly=false,也就是通过显示的调用启动,会触发全部的Lifecycle;// 当autoStartupOnly=true,也就是ApplicationContext刷新时容器自动启动,只会触发isAutoStartup方法返回true的SmartLifecycleif (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {// 3.1 获取bean的阶段值(如果没有实现Phased接口,则值为0)int phase = getPhase(bean);// 3.2 拿到存放该阶段值的LifecycleGroupLifecycleGroup group = phases.get(phase);if (group == null) {// 3.3 如果该阶段值的LifecycleGroup为null,则新建一个group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);phases.put(phase, group);}// 3.4 将bean添加到该LifecycleGroupgroup.add(beanName, bean);}});// 4.如果phases不为空if (!phases.isEmpty()) {List<Integer> keys = new ArrayList<>(phases.keySet());// 4.1 按阶段值进行排序Collections.sort(keys);// 4.2 按阶段值顺序,调用LifecycleGroup中的所有Lifecycle的start方法for (Integer key : keys) {phases.get(key).start();}}}

3.推送上下文刷新完毕事件到相应的监听器

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessary// 1.如有必要,将事件装饰为ApplicationEventApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 2.使用事件广播器广播事件到相应的监听器getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...// 3.同样的,通过parent发布事件.....if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}

这里面调用的publishEvent方法,和我们自定义的监听器调用的publishEvent是同一个方法,ContextRefreshedEvent是Spirng的一个事件称为上下文刷新完毕事件,如果我们在上下文刷新完成后要写一个发布事件,实现ApplicationListener接口即可。
我们在此举一个简单的例子。
在这里插入图片描述

在这里插入图片描述

这样,当 Spring 执行到 finishRefresh 方法时,就会将 ContextRefreshedEvent 事件推送到 MyRefreshedListener 中。
读者可以结合自定义事件对比一个和Spring提供的刷新上下文事件的区别,以便于更好的理解Spring的事件监听机制。
跟 ContextRefreshedEvent 相似的还有:ContextStartedEvent、ContextClosedEvent、ContextStoppedEvent。
好啦,Spirng的refresh方法到这里就结束啦,一共是九篇博客,实际上这也是Spirng的IOC的全部内容了,如果读者能把九篇的完全消化,那么spring的IOC也就理解的七七八八了。

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

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

相关文章

2024年9月电子学会Scratch图形化编程等级考试三级真题试卷

2024年9月Scratch图形化编程等级考试三级真题试卷 一、选择题 第 1 题 单选题 scratch运行下列程序后&#xff0c;变量“和”的取值范围是&#xff1f;&#xff08; &#xff09; A.0~12 B.0~11 C.2~11 D.2~12 第 2 题 单选题 默认角色小猫&#xff0c;scratch运行下列…

深度学习:Matplotlib篇

一、简介 1.1 什么是 Matplotlib&#xff1f; Matplotlib 是一个广泛使用的 2D 绘图库&#xff0c;它可以用来在 Python 中创建各种静态、动态和交互式的图表。无论是科学计算、数据可视化&#xff0c;还是深度学习模型的训练与评估&#xff0c;Matplotlib 都能提供强大的图形…

【Python】if选择判断结构详解:逻辑分支与条件判断

目录 &#x1f354; if选择判断结构作用 1.1 if选择判断结构的基本语法 1.2 if选择结构案例 1.3 if...else...结构 1.4 if...elif...else多条件判断结构 1.5 if嵌套结构 &#x1f354; 综合案例&#xff1a;石头剪刀布 2.1 需求分析 2.2 代码实现 2.3 随机出拳 &…

【数据结构】快速排序(三种实现方式)

目录 一、基本思想 二、动图演示&#xff08;hoare版&#xff09; 三、思路分析&#xff08;图文&#xff09; 四、代码实现&#xff08;hoare版&#xff09; 五、易错提醒 六、相遇场景分析 6.1 ❥ 相遇位置一定比key要小的原因 6.2 ❥ 右边为key&#xff0c;左边先走 …

redis详细教程(2.List教程)

List是一种可以存储多个有序字符串的数据类型&#xff0c;其中的元素按照顺序排列&#xff08;可以重复出现&#xff09;&#xff0c;可以通过数字索引来访问列表中的元素&#xff0c;索引可以从左到右或者从右到左。 Redis 列表可以通过两种方式实现&#xff1a;压缩列表&…

PVE 一键安装WIKI.js

Wiki.js 一个轻量的知识库管理工具 在PVE 的shell 下执行如下代码&#xff08;国内访问需自行调整&#xff09;&#xff0c;一键安装&#xff0c;默认使用了sqlLite 作为数据库&#xff1a; bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/wikijs…

电脑维修指南

1.输入法切换 1.右键悬浮窗 2.选择全拼 2.换壁纸 壁纸给你准备好了 https://wwyz.lanzoul.com/b00g2g2vyd 密码:da72浏览器下载解压, 然后就有了 右键, 挑选 3.清理垃圾 浏览器输入这个地址 https://wwyz.lanzoul.com/ijMin2di41ih普通下载 找一个喜欢的地方 右键, 解压 …

[SWPUCTF 2022 新生赛]py1的write up

开启靶场&#xff0c;下载附件&#xff0c;解压后得到&#xff1a; 双击exe文件&#xff0c;出现弹窗&#xff1a; 问的是异或&#xff0c;写个python文件来计算结果&#xff1a; # 获取用户输入的两个整数 num1 int(input("Enter the first number: ")) num2 int…

排序算法(冒泡,插入),希尔排序(插入升级),希尔排序和插入排序时间比较!

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;排序算法 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 一.冒泡排序&#xff1a; 时间复杂度&#xff1a;O&#xff08;N^2&#xff09;。 &#x1f3c4;‍♂️思路…

【Nas】X-DOC:搞机之PVE部署All In One(黑群晖NAS 软路由OpenWrt Docker Win10远程桌面)

【Nas】X-DOC&#xff1a;搞机之PVE部署All In One&#xff08;黑群晖NAS & 软路由OpenWrt & Docker & Win10远程桌面&#xff09; 1、原硬件配置清单&#xff1a;2、改AIO后增加配置清单&#xff1a;3、虚拟化平台PVE&#xff1a;4、搭建的关键服务&#xff1a; 1…

Web高级开发实验:EL基本运算符与数据访问

一、实验目的 掌握EL的定义&#xff0c;即Expression Language&#xff0c;用于提高编程效率。学习和掌握在开发环境中创建Java文件&#xff0c;并在jsp文件中使用EL表达式去调用其中的方法与属性等。 二、实验所用方法 上机实操 三、实验步骤及截图 1、创建javaweb项目&a…

Springboot项目中常用注解

文章目录 Springboot相关注解EnableAspectJAutoProxy(exposeProxy true)内部实现机制 EnableTransactionManagementServletComponentScanMapperScan(basePackages {"com.xxx.mapper"})ComponentScan(basePackages{"*"})lombok Data注解Controller中的相关…

jvm虚拟机介绍

Java虚拟机&#xff08;JVM&#xff09;是Java语言的运行环境&#xff0c;它基于栈式架构&#xff0c;通过加载、验证、准备、解析、初始化等类加载过程&#xff0c;将Java类文件转换成平台无关的字节码&#xff0c;并在运行时动态地将其翻译成特定平台的机器码执行。 JVM的核心…

基于SSM农业信息管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;农业技术管理&#xff0c;种植户管理&#xff0c;农产品类型管理&#xff0c;农资订单管理&#xff0c;系统管理 种植户账号功能包括&#xff1a;系统首页&#xff0c;个人中心&a…

01C++书写hello world、注释、变量、常量

#include <iostream> using namespace std; int main()//main为一个程序的入口&#xff0c;每个程序都必须仅有一个 { cout<<"hello world"<<endl; } //#输出结果为 //单行注释的符号 /* 多行注释的符号 */ //变量创建的语法&#xff1a;数据类…

OpenAI GPT-o1实现方案记录与梳理

本篇文章用于记录从各处收集到的o1复现方案的推测以及介绍 目录 Journey Learning - 上海交通大学NYUMBZUAIGAIRCore IdeaKey QuestionsKey TechnologiesTrainingInference A Tutorial on LLM Reasoning: Relevant methods behind ChatGPT o1 - UCL汪军教授Core Idea先导自回归…

shodan2---清风

注&#xff1a;本文章源于泷羽SEC&#xff0c;如有侵权请联系我&#xff0c;违规必删 学习请认准泷羽SEC学习视频:https://space.bilibili.com/350329294 实验一&#xff1a;search 存在CVE-2019-0708的网络设备 CVE - 2019 - 0708**漏洞&#xff1a;** 该漏洞存在于远程桌面…

offset Explorer连接云服务上的kafka连接不上

以上配置后报连接错误时&#xff0c;可能是因为kafka的server.properties配置文件没配置好&#xff1a; 加上面两条配置&#xff0c;再次测试连接&#xff0c;成功 listeners和advertised.listeners

C++的相关习题(2)

初阶模板 下面有关C中为什么用模板类的原因&#xff0c;描述错误的是? ( &#xff09; A.可用来创建动态增长和减小的数据结构 B.它是类型无关的&#xff0c;因此具有很高的可复用性 C.它运行时检查数据类型&#xff0c;保证了类型安全 D.它是平台无关的&#xff0c;可移植…

Vue.js 组件开发教程:从基础到进阶

Vue.js 组件开发教程:从基础到进阶 引言 在现代前端开发中,Vue.js 作为一款流行的 JavaScript 框架,以其简单易用和灵活性赢得了开发者的青睐。Vue 组件是 Vue.js 的核心概念之一,理解组件的开发和使用对构建复杂的用户界面至关重要。本篇文章将详细介绍 Vue.js 组件的开…