二、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.rhkb.cn/news/458013.html

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

相关文章

shodan2---清风

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

解读数字化转型的敏捷架构:从理论到实践的深度分析

在当今数字经济的推动下&#xff0c;企业要在瞬息万变的市场中保持竞争力&#xff0c;数字化转型已经不再是一种选择&#xff0c;而是不可避免的战略需求。然而&#xff0c;企业如何从理论到实践进行有效的转型&#xff0c;尤其是在复杂的技术环境中&#xff0c;如何通过正确的…

来源爬虫程序调研报告

来源爬虫程序调研报告 一、什么是爬虫 爬虫&#xff1a;就是抓取网页数据的程序。从网站某一个页面&#xff08;通常是首页&#xff09;开始&#xff0c;读取网页的内容&#xff0c;找到在网页中的其它链接地址&#xff0c;然后通过这些链接地址寻找下一个网页&#xff0c;这…

中小型门诊管理系统源码,云诊所管理系统源码,前端技术栈:Vue 2 , Vite , Vue Router 3

中小型门诊管理系统源码&#xff0c;云诊所管理系统源码&#xff0c; 前端技术栈&#xff1a;Vue 2 Vite Vue Router 3 Vuex 3 Element Plus Axios TypeScript Quill Election 后端技术栈&#xff1a;Spring Boot MyBatis MyBatis-Plus Spring Security Swagger2 …

使用Python计算相对强弱指数(RSI)进阶

使用Python计算相对强弱指数&#xff08;RSI&#xff09;进阶 废话不多说&#xff0c;直接上主题&#xff1a;> 代码实现 以下是实现RSI计算的完整代码&#xff1a; # 创建一个DataFramedata {DATE: date_list, # 日期CLOSE: close_px_list, # 收盘价格 }df pd.DataF…

基于丑萌气质狗--C#的sqlserver学习

#region 常用取值 查询List<string> isName new List<string> { "第一", "第二", "第三", "第四" }; List<string> result isName.Where(m > m "第三").ToList();MyDBContext myDBnew MyDBContext(…

【数据分享】中国汽车市场年鉴(2013-2023)

数据介绍 在这十年里&#xff0c;中国自主品牌汽车迅速崛起。吉利、长城、比亚迪等品牌不断推出具有竞争力的车型&#xff0c;在国内市场乃至全球市场都占据了一席之地。同时&#xff0c;新能源汽车的发展更是如日中天。随着环保意识的提高和政策的大力支持&#xff0c;电动汽车…

CSS伪元素以及伪类和CSS特性

伪元素&#xff1a;可以理解为假标签。 有2个伪元素 &#xff08;1&#xff09;::before &#xff08;2&#xff09;::after ::before <!DOCTYPE html> <html> <head><title></title><style type"text/css">body::before{con…

Android简单控件实现简易计算器

学了一些Android的简单控件&#xff0c;用这些布局和控件&#xff0c;设计并实现一个简单计算器。 计算器的界面分为两大部分&#xff0c;第一部分是上方的计算表达式&#xff0c;既包括用户的按键输入&#xff0c;也包括计算结果 数字&#xff1b;第二部分是下方的各个按键&a…

【redis】初识非关系型数据库——redis

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 初识 Redis Redis是⼀种基于键值对&#xff08;key-value&#xff09;的NoSQL数据库&#xff0c;与很多键值对数据库不同的是&#xff0c;Redis 中的值可以是由string&#xff08;字符串&#xff09;、hash&#xff0…

基于协同过滤算法的个性化课程推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

AndroidStudio部署多渠道打包环境(一)

对于游戏来说&#xff0c;需要上架国内很多家应用商店&#xff0c;还有一些小的渠道SDK&#xff0c;大大小小加起来也有几十家了&#xff0c;那么我们部署了多渠道打包环境之后就很方便了。 一 、配置游戏基本参数&#xff1a;在app下面的build.gradle文件里编辑&#xff0c; …

Java全栈经典面试题剖析4】JavaSE高级 -- 包装类,String, 类方法

目录 面试题3.1 什么是自动装箱与拆箱&#xff1f;用什么方式来装箱与拆箱&#xff1f; 面试题3.2 int和Integer有什么区别&#xff1f; 面试题3.3 Integer常量池 面试题3.4 字符串常量池 面试题3.5 这句代码创建了几个对象? String str1 new String("xyz");…

【AI大模型】深入解析 存储和展示地理数据(.kmz)文件格式:结构、应用与项目实战

文章目录 1. 引言2. 什么是 .kmz 文件&#xff1f;2.1 .kmz 文件的定义与用途2.2 .kmz 与 .kml 的关系2.3 常见的 .kmz 文件使用场景 3. .kmz 文件的内部结构3.1 .kmz 文件的压缩格式3.2 解压缩 .kmz 文件的方法3.3 .kmz 文件的典型内容3.4 .kml 文件的结构与主要元素介绍 4. 深…

python对文件的读写操作

任务:读取文件夹下的批量txt数据&#xff0c;并将其写入到对应的word文档中。 txt文件中包含&#xff1a;编号、报告内容和表格数据。写入到word当中&#xff1a;编号、报告内容、表格数据、人格雷达图以及对应的详细说明&#xff08;详细说明是根据表格中的标识那一列中的加号…

安徽对口高考Python试题选:输入一个正整数,然后输出该整数的3的幂数相加形式。

第一步&#xff1a;求出3的最高次幂是多少 guoint(input("请输入一个正整数:")) iguo a0 while i>0: if 3**i<guo: ai break ii-1print(a)#此语句为了看懂题目&#xff0c;题目中不需要打印出最高幂数 第二步…

开源模型应用落地-Qwen2-VL-7B-Instruct-vLLM-OpenAI API Client调用

一、前言 学习Qwen2-VL &#xff0c;为我们打开了一扇通往先进人工智能技术的大门。让我们能够深入了解当今最前沿的视觉语言模型的工作原理和强大能力。这不仅拓宽了我们的知识视野&#xff0c;更让我们站在科技发展的潮头&#xff0c;紧跟时代的步伐。 Qwen2-VL 具有卓越的图…

ELK日志收集

目前&#xff0c;各个微服务系统的日志都保存在各自指定的目录中&#xff0c;如果这些微服务部署在不同的服务器上&#xff0c;那么日志文件也是分散在各自的服务器上。分散的日志不利于我们快速通过日志定位问题&#xff0c;我们可以借助ELK来收集各个微服务系统的日志并集中展…

智能台灯设计(一)原理图设计

1. 前言 作者最近突发奇想&#xff0c;想自己做一个小台灯&#xff0c;设想的功能有&#xff1a;带锂电池可充电、可以调节亮度&#xff0c;后续通过增加WIFI模块实现手机控制开关功能。目前先实现最简单的功能&#xff0c;有时间再一步步完善吧。 2. 原理图设计 充电芯片使用…

B端产品常用组件及设计规则 原型图 Axure原型图 交互设计

B端产品常用组件及设计规则 本作品总结整理了B端产品原型设计时常用的组件、设计指南、常用模板等。为原型设计人员提供实用的组件和指南&#xff0c;帮助他们快速灵活地构建出更加美观、高质量的产品原型&#xff0c;更加高效地完成原型设计工作。 原型演示地址&#xff1a;…