一,Spring启动流程概览
Spring的IoC容器在实现控制反转和依赖注入的过程中,可以划分为两个阶段:
-
容器启动阶段
-
Bean实例化阶段
容器初始化
-
加载配置
-
分析配置信息
-
将Bean信息装配到BeanDefinition
-
将Bean信息注册到相应的BeanDefinitionRegistry
-
其他后续处理
容器实例化
-
根据策略实例化对象
-
装配依赖
-
Bean初始化前处理
-
对象初始化
-
对象其他处理
-
注册回调接口
二,Spring启动流程详解
准备BeanFactory
这个阶段主要是当Spring获取了BeanFactory之后,还要做些处理工作(配置工厂的上下文),如:上下文的ClassLoader和BeanPostProcessor。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 内部BeanFactory使用Context上下文的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 配置BeanFactory的Context上下文回调
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
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接口不在普通工厂中注册为可解析类型
// MessageSource 注册(找到并自动装配)为一个Bean
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.
// 注册早期的后处理器用来将内部Bean检测为ApplicationListeners。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 如果发现LoadTimeWeaver,则准备织入
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// 给类型匹配设置一个临时的ClassLoader
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册默认的environment
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 注册systemProperties
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 注册systemEnvironment
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
BeanExpressionResolver
通过将值作为表达式进行评估来解析值。它的唯一实现类是StandardBeanExpressionResolver。
PropertyEditor
Spring使用PropertyEditor的来实现对象和字符串之间的转换。有时用与对象本身不同的方式表示属性可能更为方便。如:“2019-09-13”字符串形式阅读起来更友好,但也可以将任何方便阅读的日期表现形式转换为日期对象。
Spring提供了很多内置的PropertyEditor,它们都位于org.springframework.beans.propertyeditors包中。默认情况下,大多数由BeanWrapperImpl注册。
类 | 描述 |
ByteArrayPropertyEditor | 字节数组属性编辑器。字符串将地转换为相应的字节形式。默认情况下由BeanWrapperImpl注册。 |
ClassEditor | 将表示类的字符串解析为实际类,反之亦然。当找不到类时,将抛出IllegalArgumentException。默认情况下由BeanWrapperImpl注册。 |
CustomBooleanEditor | 布尔属性编辑器。默认情况下由BeanWrapperImpl注册,但是可以通过将其自定义实例注册为自定义编辑器来覆盖。 |
CustomCollectionEditor | 集合属性编辑器,可将任何源集合转换为给定的目标集合类型。 |
CustomDateEditor | Date自定义属性编辑器,支持自定义DateFormat。 |
CustomNumberEditor | Number自定义属性编辑器。可用于任何Number子类,如Integer,Long,Float,Double。默认情况下由BeanWrapperImpl注册,但是可以通过将其自定义实例注册为自定义编辑器来覆盖。 |
FileEditor | 将字符串解析为java.io.File对象。默认情况下由BeanWrapperImpl注册。 |
InputStreamEditor | 单向属性编辑器,根据文本字符串生成(通过中间的ResourceEditor和Resource)InputStream,因此InputStream属性可以直接设置为Strings。默认情况下由BeanWrapperImpl注册。请注意,默认用法不会关闭InputStream! |
LocaleEditor | 将字符串解析为Locale对象,反之亦然(String格式为[country] [variant],与Locale的toString()方法提供的功能相同)。默认情况下由BeanWrapperImpl注册。 |
PatternEditor | 将字符串解析为java.util.regex.Pattern对象,反之亦然。 |
PropertiesEditor | 将字符串转换为Properties对象。默认情况下由BeanWrapperImpl注册。 |
StringTrimmerEditor | 修剪字符串的属性编辑器。 允许将空字符串转换为Null值。 |
URLEditor | 将URL的字符串表示形式解析为实际的URL对象。默认情况下由BeanWrapperImpl注册。 |
ResourceEditor | 资源描述符属性编辑器,可将字符串转换为Resource属性。如:将file:C:/myfile.txt或classpath:myfile.txt转换为Resource属性。 该路径可能包含$ {...}占位符,将被解析为Environment属性,如$ {user.dir}。默认情况下,无法解析的占位符将被忽略。 |
Aware感知
如果在某个Bean里面想要使用Spring框架提供的功能,可以通过Aware接口来实现。通过实现 Aware 接口,Spring 可以在启动时,调用接口定义的方法,并将 Spring 底层的一些组件注入到自定义的 Bean 中。
类 | 描述 |
ApplicationContextAware | 当ApplicationContext创建实现ApplicationContextAware接口的Bean实例时,将为该Bean实例提供对该ApplicationContext的引用。 |
ApplicationEventPublisherAware | 为Bean实例提供对ApplicationEventPublisherAware的引用。 |
BeanFactoryAware | 为Bean实例提供对BeanFactory的引用 |
BeanNameAware | 获取Bean在BeanFactory中配置的名字 |
MessageSourceAware | 为Bean实例提供对MessageSource的引用 |
EnvironmentAware | 获得Environment支持,这样可以获取环境变量 |
ResourceLoaderAware | 获得资源加载器以获得外部资源文件 |
代码示例
public class AwareBean implements ApplicationContextAware, BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("=====>" + name);
}
@Override
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
System.out.println("=====>" + ctx.getBean("awareBean"));
}
}
Xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="awareBean" class="xxx.xxx.aware.AwareBean"/>
</beans>
忽略自动装配
Spring在ConfigurableListableBeanFactory接口中提供了2个可以忽略自动装配的方法:
// 自动装配时忽略指定接口或类的依赖注入
void ignoreDependencyType(Class<?> type);
// 忽略接口实现类中存在依赖外部的Bean注入
void ignoreDependencyInterface(Class<?> ifc);
忽略自动装配的做法使得一些基础组件(如:ApplicationContext或BeanFactory)依赖在自动装配时被忽略,而由框架统一设置依赖。如ApplicationContextAware接口的设置会在ApplicationContextAwareProcessor类中完成。
示例公用xml文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="xxx.xxx.TestBean" name="testB1;testB2"/>
<bean id="human" class="xxx.xxx.autowired.Human"/>
<bean id="humanService" class="xxx.xxx.autowired.HumanService" autowire="byName"/>
<!-- 去掉下面的注释,则ignoreDependencyType生效 -->
<!--<bean class="xxx.xxx.autowired.HumanAutowiringProcessor"/>-->
<bean id="list" class="java.util.ArrayList">
<constructor-arg>
<list>
<value>foo</value>
<value>bar</value>
</list>
</constructor-arg>
</bean>
<bean id="ignoreImpl" class="xxx.xxx.autowired.IgnoreImpl" autowire="byName" />
<!-- 去掉下面的注释,则ignoreDependencyInterface生效 -->
<!--<bean class="xxx.xxx.autowired.InterfaceIgnoreProcessor"/>-->
</beans>
ignoreDependencyType
public class Human {
private String name;
public Human( String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
实现了BeanFactoryPostProcessor的忽略自动装配处理器,这里是忽略的类。
public class HumanAutowiringProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
beanFactory.ignoreDependencyType(Human.class);
}
}
ignoreDependencyInterface
接口类
public interface IgnoreInterface {
void setList(List<String> list);
}
实现类
public class IgnoreImpl implements IgnoreInterface {
private List<String> list;
@Override
public void setList(List<String> list) {
this.list = list;
System.out.println("ok.......");
}
public List<String> getList() {
return list;
}
}
实现了BeanFactoryPostProcessor的忽略自动装配处理器,这里忽略的是接口。
public class InterfaceIgnoreProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
beanFactory.ignoreDependencyInterface(IgnoreInterface.class);
}
}
BeanPostProcessor
如果想在Spring容器中完成Bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理,就需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。