Spring之启动过程源码解析

2023-11-08

Spring创建Bean,会经过一系列生命周期的流程,而Spring启动,其实就是为了后续创建Bean做一些准备工作,本篇以及下一篇文章都是来详细分析Spring的启动过程。         

目录

一、Spring启动的大致流程

二、Spring加载流程之AnnotatedBeanDefinitionReader

1.Spring程序入口

2.AnnotationConfigApplicationContext的构造函数

3.AnnotatedBeanDefinitionReader的构造函数

4.AnnotationConfigUtils中的registerAnnotationConfigProcessors()

三、refresh()底层原理流程

1.如何理解refresh()?

2.refresh()执行流程拆解分析

3.refresh()执行流程源码注释

四、BeanFactoryPostProcessor

五、BeanDefinitionRegistryPostProcessor

六、Lifecycle的使用


一、Spring启动的大致流程

通常,我们说的Spring启动,其实就是构造ApplicationContext对象以及调用refresh()方法的过程。那么这个过程会涉及到哪些操作呢?以下基于AnnotationConfigApplicationContext来进行说明:

1. 构造一个BeanFactory对象;

2. 构造BeanDefinitionReader,向BeanFactory注册各个注解模式需要的后置处理器;

3. 解析配置类,得到BeanDefinition,并注册到BeanFactory中;

 ① 解析@ComponentScan,此时就会完成扫描

 ② 解析@Import

 ③ 解析@Bean

 ④ ...

4.由于Spring启动过程中要创建非懒加载的单例Bean对象,那么就需要用到BeanPostProcessor,所以Spring在启动过程中就需要做两件事:

 4.1. 生成默认的BeanPostProcessor对象,并添加到BeanFactory中:

① AutowiredAnnotationBeanPostProcessor:处理@Autowired、@Value 注解;

② CommonAnnotationBeanPostProcessor:处理@Resource、@PostConstruct、 @PreDestroy 注解;

③ ApplicationContextAwareProcessor:处理ApplicationContextAware等回调
 4.2. 找到外部用户自定义的BeanPostProcessor对象(类型为BeanPostProcessor的Bean对象),并添加到BeanFactory中;

5. ApplicationContext支持国际化,需要初始化MessageSource对象;

6. ApplicationContext支持事件机制,还需要初始化ApplicationEventMulticaster对象;

7. 把用户定义的ApplicationListener对象添加到ApplicationContext中,等Spring启动完了就要发布事件了;

8. 创建非懒加载的单例Bean对象,并存在BeanFactory的单例池中;

9. 调用LifecycleBean的start()方法;

10. 发布ContextRefreshedEvent事件;

二、Spring加载流程之AnnotatedBeanDefinitionReader

1.Spring程序入口

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

2.AnnotationConfigApplicationContext的构造函数

AnnotationConfigApplicationContext是Spring的高级容器,有多个构造方法,以下是基于AnnotationConfigApplicationContext(Class<?>... componentClasses)来分析,在这个构造方法中,首先会执行自己的无参构造方法---this(),在this()中会先执行父类GenericApplicationContext的默认构造方法;

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
	   /**构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
	    *这里由于它有父类,所以会先调用父类的构造方法,初始化DefaultListableBeanFactory
		*AnnotationConfigApplicationContext容器无参构造器--->父类GenericApplicationContext无参构造器,创建this.beanFactory = new DefaultListableBeanFactory();
		*/
		this();
		//注册相关信息
		register(componentClasses);
		//刷新容器---核心
		refresh();
	}
public GenericApplicationContext() {
    // 初始化一个beanFactory
	this.beanFactory = new DefaultListableBeanFactory();
}

这个DefaultListableBeanFactory,非常重要,Spring加载的bean都会放到这个Bean工厂中,
当然GenericApplicationContext的父类AbstractApplicationContext,包括AbstractApplicationContext的父类DefaultResourceLoader都有默认构造方法的;

public AbstractApplicationContext() {
	this.resourcePatternResolver = getResourcePatternResolver();
}

public DefaultResourceLoader() {
}

这些提前初始化的属性到后面都会用到,以下是继承关系图:

3.构造AnnotatedBeanDefinitionReader

回到AnnotationConfigApplicationContext(Class<?>... componentClasses)构造方法中的this(),

构造AnnotatedBeanDefinitionReader,主要作用是对BeanFactory进行设置和添加一些基础的PostProcessor(后置处理器),同时可以通过reader进行BeanDefinition的注册;

public  AnnotationConfigApplicationContext() {
	StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
	/** 什么是bean定义 ? BeanDefinition
	 * 创建一个读取注解的Bean定义读取器,它的register()方法能够将类解析成为一个BeanDefination,然后将BeanDefination对象存到beanDefinationMap中,而beanDefinationMap是在Bean工厂中
	 * 完成了Spring内部BeanDefinition的注册(主要是后置处理器)
	 * 额外会创建StandardEnvironment
	 */
	this.reader = new AnnotatedBeanDefinitionReader(this);//this 指的就是DefaultListableBeanFactory
	createAnnotatedBeanDefReader.end();
	/** 创建BeanDefinition扫描器,可以用来扫描包或者类继而转换为BeanDefinition
	 * Spring默认的扫描器其实不是这个scanner对象,而是在后面自己又重新new了一个ClassPathBeanDefinitionScanner
	 * Spring在执行工程后置处理器ConfigurationClassPostProcessor时,去扫描包时会new一个ClassPathBeanDefinitionScanner
	 * 这里的scanner仅仅是为了程序员可以手动调用AnnotationConfigApplicationContext对象的scan方法
	 */
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

对于AnnotatedBeanDefinitionReader()构造函数里面的参数registry其实就是DefaultListableBeanFactory;

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
	this(registry, getOrCreateEnvironment(registry));
}

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
	this.registry = registry;
	// 解析器,用来解析@Conditional注解的
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	/** registerAnnotationConfigProcessors,向BeanFactory注册各个注解模式需要的后置处理器
	 * 根据名字顾名思义就是->注册注解配置的处理器,也就是这个方法里面会注册一些用于处理注解的处理器
	 */
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

4.AnnotationConfigUtils中的registerAnnotationConfigProcessors()

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
	registerAnnotationConfigProcessors(registry, null);
}

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    // 获取beanFactory也就是DefaultListableBeanFactory
	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
        /**
		 * 	设置比较器,它是一个Comparator,可以用来进行排序,比如new ArrayList<>().sort(Comparator),主要能解析@Order和@Priority
		 * 	会获取某个对象上的Order注解或者通过实现Ordered接口所定义的值进行排序,在日常开发中可以利用这个类来进行排序
		 */
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		/**
		 * 设置依赖注入的候选处理器,用来判断某个Bean能不能用来进行依赖注入
		 * 可以看到只要不是ContextAnnotationAutowireCandidateResolver类型  直接升级为最强类型
		 */
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
		beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

	/**注册ConfigurationClassPostProcessor类型的BeanDefinition,ConfigurationClassPostProcessor是一个工厂后置处理器
	 * 这个后置处理器非常重要,基本上类上面的注解都在这里面判断并解析,Spring的包扫描也在里面完成
	 */
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	/**
	 * 注册AutowiredAnnotationBeanPostProcessor类型的BeanDefinition
	 * 处理@Autowired注解的,它是一个bean的后置处理器,在bean的属性注入的时候会用到
	 */
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	/**
	 * 注册CommonAnnotationBeanPostProcessor类型的BeanDefinition
	 * 处理一些公共注解的,它是一个bean的后置处理器,可以处理@PostConstruct和@PreDestroy还有@Resource等
 	 */
	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// 注册PersistenceAnnotationBeanPostProcessor类型的BeanDefinition
	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

		/**
		 * 注册EventListenerMethodProcessor类型的BeanDefinition,用来处理@EventListener注解的
		 * Spring实现事件监听的方式有很多种,其中一种就是在方法上添加@EventListener注解
 		 */
		if (
	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}

	// 注册DefaultEventListenerFactory类型的BeanDefinition,用来处理@EventListener注解的
	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}

三、refresh()底层原理流程

1.如何理解refresh()?

	/**
	 * Load or refresh the persistent representation of the configuration, which
	 * might be from Java-based configuration, an XML file, a properties file, a
	 * relational database schema, or some other format.
	 * <p>As this is a startup method, it should destroy already created singletons
	 * if it fails, to avoid dangling resources. In other words, after invocation
	 * of this method, either all or no singletons at all should be instantiated.
	 * @throws BeansException if the bean factory could not be initialized
	 * @throws IllegalStateException if already initialized and multiple refresh
	 * attempts are not supported
	 */
	void refresh() throws BeansException, IllegalStateException;

这是ConfigurableApplicationContext接口上refresh()方法的注释,意思是:加载或刷新持久化的配置,可能是XML文件、属性文件或关系数据库中存储的;由于这是一个启动方法,如果失败,它应 该销毁已经创建的单例,以避免占用资源,换句话说,在调用该方法之后,应该实例化所有的单例, 或者根本不实例化单例 。 有个地方需要注意:ApplicationContext关闭之后不代表JVM也关闭了,ApplicationContext是属于JVM的,ApplicationContext也是JVM中的一个对象。

在Spring的设计中,也提供可以刷新的ApplicationContext和不可以刷新的ApplicationContext, 比如:

AbstractRefreshableApplicationContext extends AbstractApplicationContext

就是可以刷新的;

GenericApplicationContext extends AbstractApplicationContext

就是不可以刷新的。 AnnotationConfigApplicationContext继承的是GenericApplicationContext,所以它是不能刷新的; AnnotationConfigWebApplicationContext继承的是 AbstractRefreshableWebApplicationContext,所以它是可以刷新的,上面说的不能刷新是指不能重复刷新,只能调用一次refresh方法,第二次时会报错。

2.refresh()执行流程拆解分析

2.1. prepareRefresh():

 ① 可以允许子容器设置一些内容到Environment中;

 ② 验证Environment中是否包括了必须要有的属性;

2.2. obtainFreshBeanFactory():进行BeanFactory的refresh,在这里会去调用子类的 refreshBeanFactory方法,具体子类是怎么刷新的得看子类的实现,最后再调用子类的 getBeanFactory方法,重新得到一个BeanFactory;

2.3. prepareBeanFactory(beanFactory):

 ① 设置beanFactory的类加载器,由于创建bean是由Bean工厂来创建,所有如果设置了类加载器,会把类加载器设置到Bean工厂中;

 ② 设置SpringEL表达式解析器:StandardBeanExpressionResolver,用来解析Spring中的表达式,例如: @Value("#{}"); 

 ③ 添加PropertyEditorRegistrar:ResourceEditorRegistrar,属性编辑器注册器,用来注册一些默认的PropertyEditor ;

 ④ 添加一个Bean的后置处理器:ApplicationContextAwareProcessor,是一个BeanPostProcessor,用来执行EnvironmentAware、ApplicationContextAware、ApplicationEventPublisherAware 等回调方法

 ⑤ 添加ignoredDependencyInterface:可以向这个属性中添加一些接口,如果某个类实现了其中的一个或多个接口,并且这个类中的某些set方法在接口中也存在,那么这个set方法在自动注入的 时候是不会执行的,比如EnvironmentAware这个接口,如果某个类实现了这个接口,那就必须实现它的setEnvironment方法,而这是一个set方法,和Spring中的autowire是冲突 的,那么Spring在自动注入时是不会调用setEnvironment方法的,而是等到回调Aware接口时再来调用(注意,这个功能仅限于xml的autowire,@Autowired注解是忽略这个属性的,这些接口有 EnvironmentAware

EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware

MessageSourceAware、ApplicationContextAware

其实在容器启动构造BeanFactory(DefaultListableBeanFactory)的时候,ignoredDependencyInterface就已经提前添加了另外三个,分別是BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

2.4. 添加resolvableDependencies:在byType进行依赖注入时,会先从这个属性中根据类型找bean

① BeanFactory.class:当前BeanFactory对象

② ResourceLoader.class:当前ApplicationContext对象

③ ApplicationEventPublisher.class:当前ApplicationContext对象

④ ApplicationContext.class:当前ApplicationContext对象

2.5. 添加一个Bean的后置处理器:ApplicationListenerDetector,是一个 BeanPostProcessor,用来判断某个Bean是不是ApplicationListener,如果是则把这个 Bean添加到ApplicationContext中去,注意一个ApplicationListener只能是单例的;

2.6. 添加一个Bean的后置处理器:LoadTimeWeaverAwareProcessor,是一个 BeanPostProcessor,用来判断某个Bean是不是实现了LoadTimeWeaverAware接口,如果实现了则把ApplicationContext中的loadTimeWeaver回调setLoadTimeWeaver方法设置给该Bean;

2.7. 添加一些单例bean到单例池:

① "environment":Environment对象

② "systemProperties":System.getSystemProperties()返回的Map对象

③  "systemEnvironment":System.getSystemEnvironment)返回的Map对象

④ "applicationStartup":DefaultApplicationStartup对象

2.8. postProcessBeanFactory(beanFactory) : 提供给AbstractApplicationContext的子类进行扩 展,具体的子类,可以继续向BeanFactory中再添加一些东西;

2.9. invokeBeanFactoryPostProcessors(beanFactory):执行BeanFactoryPostProcessor,到这一步,在BeanFactory中已经存在一个BeanFactoryPostProcessor: ConfigurationClassPostProcessor,它也是一个BeanDefinitionRegistryPostProcessor

 2.9.1. 执行通过ApplicationContext添加进来的BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry()方法 ;

 2.9.2. 执行BeanFactory中实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry()方法 ;

 2.9.3. 执行BeanFactory中实现了Ordered接口的BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry()方法 ;

 2.9.4. 执行BeanFactory中其他的BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry()方法 ;

 2.9.5. 执行上面所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法 ;

 2.9.6. 执行通过ApplicationContext添加进来的BeanFactoryPostProcessor的 postProcessBeanFactory()方法 ;

 2.9.7. 执行BeanFactory中实现了PriorityOrdered接口的BeanFactoryPostProcessor的 postProcessBeanFactory()方法 ;

 2.9.8. 执行BeanFactory中实现了Ordered接口的BeanFactoryPostProcessor的  postProcessBeanFactory()方法 ;

 2.9.9. 执行BeanFactory中其他的BeanFactoryPostProcessor的postProcessBeanFactory()方法;

2.10. registerBeanPostProcessors(beanFactory):因为上面的步骤完成了扫描,这个过程中我们可能自己定义了一些BeanPostProcessor,在这一步就会把BeanFactory中所有的 BeanPostProcessor找出来实例化得到相应的对象,并添加到BeanFactory中去(属性 beanPostProcessors),最后再重新添加一个ApplicationListenerDetector对象(之前其实就添加了过,这里是为了把ApplicationListenerDetector移动到最后);

2.11. initMessageSource():ApplicationContext是支持国际化的,但不是自己完全去实现,而是利用MessageSource去实现的,而MessageSource通常是需要我们自己去定义的,如果BeanFactory中存在一个叫做"messageSource"的 BeanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContext的 messageSource属性,让ApplicationContext拥有国际化的功能;

2.12.initApplicationEventMulticaster():初始化事件监听多路广播器,如果BeanFactory中存在一个叫做"applicationEventMulticaster"的BeanDefinition,就会把这个Bean对象创建出来并赋值给ApplicationContext的applicationEventMulticaster属性,如果没有,则默认采用SimpleApplicationEventMulticaster,让ApplicationContext拥有事件发布的功能;

2.13. onRefresh():提供给AbstractApplicationContext的子类进行扩展;

2.14. registerListeners():从BeanFactory中获取ApplicationListener类型的beanName,然后添加 到ApplicationContext中的事件广播器applicationEventMulticaster中去,到这一步因为 FactoryBean还没有调用getObject()方法生成Bean对象,所以这里要在根据类型找一下 ApplicationListener,记录一下对应的beanName;

2.15. finishBeanFactoryInitialization(beanFactory):完成BeanFactory的初始化,主要就是实例化 非懒加载的单例Bean;

2.16. finishRefresh():BeanFactory的初始化完后,就到了Spring启动的最后一步了,

 ① 初始化ApplicationContext的lifecycleProcessor,默认情况下设置的是     DefaultLifecycleProcessor ;

 ② 调用lifecycleProcessor的onRefresh()方法,如果是DefaultLifecycleProcessor,那么会获取所 有类型为Lifecycle的Bean对象,然后调用它的start()方法,这就是ApplicationContext的生命 周期扩展机制;

@Override
public void onRefresh() {
	startBeans(true);
}

private void startBeans(boolean autoStartupOnly) {
	Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
	Map<Integer, LifecycleGroup> phases = new TreeMap<>();

	// 按每个Bean的phase进行分组
	lifecycleBeans.forEach((beanName, bean) -> {
		if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
			 int phase = getPhase(bean);
			 phases.computeIfAbsent(
					phase,
					p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
			).add(beanName, bean);
		}
	});

	// 按分组执行start()
	if (!phases.isEmpty()) {
			phases.values().forEach(LifecycleGroup::start);
	}
}


protected Map<String, Lifecycle> getLifecycleBeans() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	Map<String, Lifecycle> beans = new LinkedHashMap<>();
    //获取beanFactory中所有Lifecycle类型的beanName
	String[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
	for (String beanName : beanNames) {
		 String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);
		 boolean isFactoryBean = beanFactory.isFactoryBean(beanNameToRegister);
		 String beanNameToCheck = (isFactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);

		// 如果所定义的Lifecycle的Bean是单例并且(不是FactoryBean或是Lifecycle类型或是SmartLifecycle类型的)
		if ((beanFactory.containsSingleton(beanNameToRegister) &&
					(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||
					matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)) {
			Object bean = beanFactory.getBean(beanNameToCheck);
			if (bean != this && bean instanceof Lifecycle) {
				beans.put(beanNameToRegister, (Lifecycle) bean);
			}
		}
	}
	return beans;
}

③ 发布ContextRefreshedEvent事件;

3.refresh()执行流程源码注释

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// 启动前的准备工作
			prepareRefresh();
			/*
			 * 由于web项目中并不会先引入DefaultListableBeanFactory,在这里通知子类刷新BeanFactory,例如:AbstractRefreshableApplicationContext
			 * 而我们是使用new AnnotationConfigApplicationContext()的方式,就是直接返回之前引入的DefaultListableBeanFactory
			 * Tell the subclass to refresh the internal bean factory.
             * 这里会判断能否刷新,并且返回一个BeanFactory
			 * 对于能进行重复刷新的子容器,刷新不代表完全清空,主要是先执行Bean的销毁,然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 准备BeanFactory
			// 1. 设置BeanFactory的类加载器、SpringEL表达式解析器、类型转化注册器
			// 2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象
			// 3. 记录ignoreDependencyInterface
			// 4. 记录ResolvableDependency
			// 5. 添加三个单例Bean
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 留的扩展方法,子类来设置一下BeanFactory
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

				// Invoke factory processors registered as beans in the context.
				// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
				// 默认情况下:
				// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition
				// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor
				// 这里会用ConfigurationClassPostProcessor这个类进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中
				// 再具体一点就是执行ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry()方法进行扫描
				// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				invokeBeanFactoryPostProcessors(beanFactory);  // scanner.scan()

				// Register bean processors that intercept bean creation.
				// 将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去
				registerBeanPostProcessors(beanFactory);

				beanPostProcess.end();

				// Initialize message source for this context.
				// 设置ApplicationContext的MessageSource,可以是用户设置的,或者是DelegatingMessageSource
				// ApplicationContext是支持国际化的,但不是自己完全去实现,而是利用MessageSource去实现的,而MessageSource通常是需要我们自己去定义的
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件监听多路广播器,设置ApplicationContext的applicationEventMulticaster,可以是用户设置的,或者是默认的SimpleApplicationEventMulticaster
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 给子类的模板方法
				onRefresh();

				// Check for listener beans and register them.
				// 把定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件
				registerListeners();

				/**
				 * Instantiate all remaining (non-lazy-init) singletons.
				 * 创建非懒加载的单例bean,创建bean的时候需要用到BeanPostProcessor,而BeanPostProcessor都是存在于beanPostProcessors中
				 * 而registerBeanPostProcessors(beanFactory)就是向BeanFactory的beanPostProcessors中添加BeanPostProcessor的对象
				 */
				finishBeanFactoryInitialization(beanFactory);

				// 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();
				contextRefresh.end();
			}
		}
	}

四、BeanFactoryPostProcessor

BeanPostProcessor表示Bean的后置处理器,是用来对Bean进行加工的,类似的, BeanFactoryPostProcessor理解为BeanFactory的后置处理器,用来用对BeanFactory进行加工的, Spring支持用户自定义BeanFactoryPostProcessor的实现类,来对BeanFactory进行加工,比例如:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
   throws BeansException {
   BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
   beanDefinition.setAutowireCandidate(false);
   }
}

以上代码,就利用了BeanFactoryPostProcessor来拿到BeanFactory,然后获取BeanFactory内的某个BeanDefinition对象并进行修改,这一步是发生在Spring启动时,创建单例Bean之前的,所以此时对BeanDefinition就行修改是会生效的。 注意:在ApplicationContext内部有一个核心的DefaultListableBeanFactory,它实现了 ConfigurableListableBeanFactory和BeanDefinitionRegistry接口,所以ApplicationContext和 DefaultListableBeanFactory是可以注册BeanDefinition的,而ConfigurableListableBeanFactory是不能注册BeanDefinition的,只能获取BeanDefinition,对BeanDefinition做修改。

五、BeanDefinitionRegistryPostProcessor

Spring还提供了一个BeanFactoryPostProcessor的子接口: BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
   void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws
   BeansException;
}

我们可以看到BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,并新 增了一个方法,注意方法的参数为BeanDefinitionRegistry,如果我们自定义一个类来实现 BeanDefinitionRegistryPostProcessor,那么在postProcessBeanDefinitionRegistry()方法中就可 以注册BeanDefinition了。比如:

@Component
public class MyBeanDefinitionRegistryPostProcessor implements
BeanDefinitionRegistryPostProcessor {
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws
  BeansException {
     AbstractBeanDefinition beanDefinition =
     BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
     beanDefinition.setBeanClass(User.class);
     registry.registerBeanDefinition("user", beanDefinition);
  }
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
  throws BeansException {
    BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
    beanDefinition.setAutowireCandidate(false);
  }
}

六、Lifecycle的使用

Lifecycle表示的是ApplicationContext的生命周期,可以定义一个SmartLifecycle来监听 ApplicationContext的启动和关闭:

/** 
 *  Bean有生命周期,对于Spring容器而言也有一个生命周期,如果我们想去监听Spring容器什么时候创建好?有以下做法:
 *  1.监听Spring容器发布的这个事件 :publishEvent(new ContextRefreshedEvent(this))
 *  2.监听当前Spring容器是否启动完了,如下做法:
 */
@Component
//@Scope("prototype")
public class MyLifecycle implements SmartLifecycle {

	private boolean isRunning;

	/**
	 * Spring容器启动完了会调用start()
	 */
	@Override
	public void start() {
		System.out.println("start...");
		isRunning=true;
	}

	/**
	 * 调start()之前会执行isRunning(),判断当前是不是在运行,如果当前不是处于运行的过程中,才会调start()
	 * 如果是在运行(true)才能调stop方法
	 * 要触发stop(),要调用context.close(),或者注册关闭钩子(context.registerShutdownHook())
	 */
	@Override
	public void stop() {
		System.out.println("stop...");
	}


	@Override
	public boolean isRunning() {
		return isRunning;
	}

	//分组
	@Override
	public int getPhase() {
		return 1;
	}
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring之启动过程源码解析 的相关文章

  • 使用 Intellij 2017.2 /out 目录构建会重复 /build 目录中的文件

    更新到 Intellij 2017 2 后 构建我的项目会创建一个 out包含生成的源文件和资源文件的目录 这些文件与已包含的文件重复 build并导致duplicate class生成的类的编译器错误 关于 Gradle 或 Intell
  • 如何在谷歌地图中使用latlng字符串数组绘制多边形

    在我的应用程序中 我有包含 imagview 的 recyclerview 并且该 imageview 通过使用我存储在 sqlite 中的坐标包含静态地图图像 当我单击该图像时 我将该字符串数组格式的坐标传递给其他地图活动 然后使用该字符
  • Junit Mockito 测试一切

    我现在正在寻找更多时间但没有结果 请帮忙 这是我要测试的课程 public class DBSelectSchema extends Database private static final Logger LOG Logger getLo
  • 为什么byteArray的长度是22而不是20?

    我们尝试从字符串转换为Byte 使用以下 Java 代码 String source 0123456789 byte byteArray source getBytes UTF 16 我们得到一个长度为 22 字节的字节数组 我们不确定这个
  • 为什么 hibernate 在一张表中保存两个 @OneToMany 列表?

    想象一下使用 Hibernate 和 JPA 的简化代码如下 Entity class C Id GeneratedValue public long id MappedSuperclass abstract class A Id Gene
  • Maven 2 未运行 Junit 4 测试

    我在确保运行 Junit4 测试时遇到问题 同样的问题也被报告在https stackoverflow com questions 2021771 sort newest sort top https stackoverflow com q
  • Tomcat - 多个 webapps 文件夹

    是否可以有多个文件夹来放置要部署的应用程序 这些是如何定义的 是否可以将一个文件夹限制为仅是 domain com 的应用程序 而不是其他域 Thanks 看一眼conf server xml
  • 如何知道 glassfish 是什么 - 完整平台或网络配置文件?

    我已经安装了glassfish 我可以跑 asadmin version 它显示了它是什么版本 但如何知道它是 完整平台 还是 Web 配置文件 你可以使用 glassfish4 bin gt asadmin list containers
  • “未找到 JAVA 路径。请检查 JAVA 是否已安装。”初始化 RSelenium 时出错

    我正在尝试启动一个 RSelenium 会话到 webscrape 但是 当运行此代码时 driver lt rsDriver browser c chrome chromever 76 0 3809 126 port 4444L 我收到此
  • 如何找到 Oracle 数据库的 URL?

    如何找到 Oracle 数据库的 URL 和端口 Example jdbc oracle thin host port dbName 用户名 密码 是否有我可以查看的 SQL 命令或日志 配置文件 对于甲骨文来说 有一个tnsnames o
  • 有界通配符相关的编译器错误

    我想知道这段代码有什么问题 Map 但我试图说得更具体 这个问题在这个旧的 Apache 线程 ht
  • 读取不失真的灰度 PNG 图像文件

    我需要读取和处理大量的灰度 PNG 文件 我的意思是 如果它们在 Photoshop 或 GIMP 中打开 则图像模式为灰度 而不是具有灰度值的 RGB 图像 ImageIO 似乎没有实现这一点 它似乎将所有图像文件视为 sRGB 这会破坏
  • Java 泛型:将 Object o 的类与 进行比较

    假设我有以下课程 public class Test
  • Java 空值检查

    我有一个thread1 if object null object play 和另一个thread2可以写null into object随时参考 我将同时运行这些线程 我知道thread2可以重写object后参考null检查并会抛出Nu
  • 将字符串转换为字符并按降序排序(ascii)

    我正在创建一个程序 该程序将使用户输入整数 一个接一个 存储在数组中并按降序显示整数 该程序还要求用户输入一个字符串 使用以下命令将其转换为字符string toCharArray 我已经正确地按降序显示整数 问题是我不知道如何按降序显示字
  • logcat 信息出现在 Android Studio 的“运行”选项卡中

    我的 android studio 运行选项卡很简单 然后它变得更难并给我更多信息 例如 logcat 中的信息 如何禁用或删除第二张图片中出现的更多信息并返回到第一张图片中的第一个外观 我只需要正在运行的 flutter 应用程序的日志输
  • 使用 InputStream 通过 TCP 套接字接收多个图像

    每次我从相机捕获图像时 我试图将多个图像自动从我的 Android 手机一张一张地发送到服务器 PC 问题是read 函数仅在第一次时阻塞 因此 从技术上讲 只有一张图像被接收并完美显示 但在那之后当is read 回报 1 该功能不阻塞
  • Spring Boot中服务接口类的用途

    我的问题是关于接口类的使用 我对 Spring 还很陌生 所以如果这过于简单 请耐心等待 首先 当您可以在 BoxService 中声明 find all 时 这里拥有 IBoxService 接口有什么意义 其次 在控制器中如何使用IBo
  • 在java中打印阿拉伯字符串

    我试图在 java 中显示阿拉伯语文本 但它显示垃圾字符 示例 或有时在我打印时仅显示问号 我如何才能打印阿拉伯语 我听说它与unicode和UTF 8有关 这是我第一次使用语言 所以不知道 我正在使用 Eclipse Indigo IDE
  • 将 JSON 发送到 Spring MVC 控制器

    我正在尝试将 JSON 发送到 Spring MVC 控制器 在 Spring MVC 方面 一切都配置正确 下面是代码 但似乎没有运行

随机推荐

  • Arthas线上监控诊断产品[学习笔记]

    1下载启动arthas tunnel server Arthas Tunnel arthasarthas 使用文档https arthas aliyun com doc tunnel html E4 B8 8B E8 BD BD E9 83
  • Ceph集群生产环境安装部署

    前言 ceph的组件以及工作流程非常的复杂 是一个庞大的系统 在尝试ceph之前尽量多查阅官方的文档 理解ceph的mon osd mds pg pool等各组件 Unit的协同工作方式 Ceph官方文档 一 配置规划 二 部署 1 ntp
  • 超强OCR文字识别软件 图像文字识别软件工具-独有直接屏幕截图识别功能

    原文地址 http blog sina com cn s blog 4d36b4ba0100vnzc html 相关文章 1 Screen OCR 屏幕画面截屏工具 13 5 官方绿色版 http www newasp net soft 6
  • 人的一生(none)

    曾仕强 情绪管理 要有理想 情绪负债 享受错误的决定 错误嘴巴推给别人心里推给自己 没有人会因为你的抱怨而改变 只有改变自己 立场不同 讲话不一样 反求诸己 治标方法 散步 发泄 要看开 不要看破 被看待事情的观点所困扰 而不是被事情所困扰
  • linux 系统命令行查看电池剩余电量

    proc acpi battery BAT0 state 文件里的remaining capacity表示剩余电量 proc acpi battery BAT0 info 文件里的last full capacity表示满电量 如果有多块电
  • python数据分析——pyecharts折线图全解(小白必看)

    折线图是排列在工作表的列或行中的数据可以绘制到折线图中 折线图可以显示随时间 根据常用比例设置 而变化的连续数据 因此非常适用于显示在相等时间间隔下数据的趋势 下面我给大家介绍一下如何用pyecharts画出各种折线图 1 基本折线图 im
  • 【WSL2】win11创建秒级启动openEuler虚拟机

    前言 Windows上安装openEuler虚拟机 现在大多采用的是 vmware workstation virtual box 方案 可以完整地体验openEuler系统以及使用图形界面 这个方案的缺点是启动慢 资源消耗大 性能损耗大
  • VMware虚拟机安装+Ubuntu安装+VMware Tools安装+Ubuntu下g++编译器的安装+虚拟机中系统的移动

    一 VMware虚拟机安装 Ubuntu安装 本人VMware15 Pro Ubuntu18 04 06 LTS 该部分安装可见博客 提示 VMware15 Pro可在win7及以上系统中安装 VMware Workstation 16 P
  • Libevent使用例子,从简单到复杂

    出处 http blog csdn net luotuo44 article details 39670221 本文从简单到复杂 展示如何使用libevent 网上的许多例子都是只有服务器端的 本文里面客户端和服务器端都有 以飨读者 关于l
  • 3-rospy介绍

    Client Library 1 提供ROS编程的库 2 例如建立node 发布消息 调用服务 3 提供了如下几种client library roscpp rospy roslisp rospy的组成 1 Node 2 Topic 3 S
  • vscode编译多文件的方法(C和C++通用)

    vscode编译多文件的方法 1 新建一个文件夹作为工程 我这里以struct为工程文件夹 其中 xixi c 和 xixi h 是该工程下list文件夹里的内容 xixi c include xixi h include
  • 简单注册界面

    register html div class form container div
  • webpack 转换 ES6高级语法 bable插件 module rules

    在webpack中只能处理一部分es6语法 一些高级的ES6或者ES7 webpack处理不了 借助第三方loader处理 会将结果打包到main js loader 通过Bable可以转换 webpack中运行 如下两套命令 去安装bab
  • Go分布式缓存 使用 Protobuf 通信(day7)

    Go分布式缓存 使用 Protobuf 通信 day7 为什么要使用 protobuf 使用 protobuf 进行节点间通信 编码报文 提高效率 代码约50行 1 为什么要使用 protobuf protobuf 即 Protocol B
  • c语言之输出

    c语言之输出 1 printf 功能 格式化输出函数 一般用于向标准输出设备按照规定的格式输出信息 头文件
  • java hasnextstring_Java – ListIterator和hasNext

    如果列表只有一个元素 那就更清楚了 让我们说 b hasNext 实际上会返回true 而next 会读取它 迭代将在此之后结束 说明 如果你打电话给Iterator lt Object gt 任何非空列表上的it list iterato
  • flutter 左右循环跑马灯,html实现

    import dart async import package flutter cupertino dart import package flutter material dart import package flutter html
  • js数组去重的方法

    Js数组去重的方法 1 ES6 Set方法去重 1 利用ES6 Set去重 let arr 1 2 3 25 4 1 2 3 function deduplicationBySet array return Array from new S
  • 半个小时内,用神经网络识别无人机航拍图像

    上一篇只要九分钟 用神经网络构建人脸比对模型的文章发出去之后 承蒙大家厚爱 得到了不少反馈 不少朋友希望能让我讲讲如何做图像识别 正好 TeguCV 的安装包里有一个测试数据集是我们用无人机航拍的车辆照片 就用它来做个教程吧 前情提要 Ma
  • Spring之启动过程源码解析

    Spring创建Bean 会经过一系列生命周期的流程 而Spring启动 其实就是为了后续创建Bean做一些准备工作 本篇以及下一篇文章都是来详细分析Spring的启动过程 目录 一 Spring启动的大致流程 二 Spring加载流程之A