Bean 的配置方式
XML 方式配置 Bean
新建 Student 类,有 name、age、classList 三个属性,HelloService 类有 Student 属性。
public class Student {
private String name;
private Integer age;
private List<String> classList;
// getter and setter
}
public class HelloService {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public String hello() {
return student.toString();
}
}
在 resources 目录下新建 Spring 配置文件 demo.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">
<!-- student 配置 -->
<bean id="helloService" class="store.xianglin.sb2.ioc.xml.HelloService">
<property name="student" ref="student"/>
</bean>
</beans>
在 test 目录下新建测试类,测试 HelloService 类的 hello 方法。
@SpringBootTest
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:ioc/demo.xml")
public class HelloServiceTest {
@Resource
private HelloService helloService;
@Test
public void testHello() {
System.out.println(helloService.hello());
}
}
方式一、通过属性注入。
<bean id="student" class="store.xianglin.sb2.ioc.xml.Student">
<property name="name" value="zhangsan"/>
<property name="age" value="13"/>
<property name="classList">
<list>
<value>math</value>
<value>english</value>
</list>
</property>
</bean>
方式二、通过构造器注入。在 Student 类中创建两个参数的构造器,在 demo.xml 中使用 constructor-arg 标签注入。
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
<bean id="student" class="store.xianglin.sb2.ioc.xml.Student">
<constructor-arg index="0" value="zhangsan"/>
<constructor-arg index="1" value="13"/>
<property name="classList">
<list>
<value>math</value>
<value>english</value>
</list>
</property>
</bean>
新建抽象类 Animal,定义抽象方法 getName,定义子类 Cat 和 Dog。新建工厂类 AnimalFactory,定义静态方法 getAnimal、实例方法 getAnimalInstance,根据入参返回 Animal 的实例。
public abstract class Animal {
abstract String getName();
}
public class Cat extends Animal {
@Override
String getName() {
return "cat";
}
}
public class Dog extends Animal{
@Override
String getName() {
return "dog";
}
}
public class AnimalFactory {
public static Animal getAnimal(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
}
return null;
}
public Animal getAnimalInstance(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
}
return null;
}
}
方式三、静态工厂方法注入。
<bean id="dog" class="store.xianglin.sb2.ioc.xml.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="dog"/>
</bean>
<bean id="cat" class="store.xianglin.sb2.ioc.xml.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="cat"/>
</bean>
方式四、实例工厂方法注入。
<bean id="animalFactory" class="store.xianglin.sb2.ioc.xml.AnimalFactory"/>
<bean id="dog1" factory-bean="animalFactory" factory-method="getAnimalInstance">
<constructor-arg value="dog"/>
</bean>
<bean id="cat1" factory-bean="animalFactory" factory-method="getAnimalInstance">
<constructor-arg value="cat"/>
</bean>
注解方式配置 Bean
方式一、使用 @Component 注解,直接在 HelloService 类上添加 @Component,将其注入到容器中。
@Component
public class HelloService {
@Resource
private Animal animal;
public Animal getAnimal() {
return animal;
}
public void setAnimal(Animal animal) {
this.animal = animal;
}
public String hello() {
return animal.getName();
}
}
方式二、使用 @Bean 注解,在 @Configuration 注解标注的配置类中通过 @Bean 注解注入 Bean。
@Configuration
public class BeanConfiguration {
@Bean("dog")
public Animal getDog() {
return new Dog();
}
}
方式三、实现 FactoryBean 接口。
@Component
public class MyCat implements FactoryBean<Animal> {
@Override
public Animal getObject() {
return new Cat();
}
@Override
public Class<?> getObjectType() {
return Animal.class;
}
}
方式四、实现 BeanDefinitionRegistryPostProcessor 接口,在 postProcessBeanDefinitionRegistry 方法中添加 BeanDefinition。
@Component
public class MyBeanRegister implements BeanDefinitionRegistryPostProcessor, InstantiationAwareBeanPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注入 BeanDefinition
var definition = new RootBeanDefinition();
definition.setBeanClass(Monkey.class);
registry.registerBeanDefinition("monkey", definition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 为 BeanDefinition 注入属性
var monkey = beanFactory.getBeanDefinition("monkey");
monkey.getPropertyValues().addPropertyValue("property", "value from postProcessBeanFactory");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// 自定义创建 Bean,不会执行后续的 doCreateBean 方法以及属性注入等
if (beanClass.equals(Monkey.class)) {
return new Monkey();
}
return null;
}
}
方式五、实现 ImportBeanDefinitionRegistrar,通过 @Import 导入。
public class MyBeanImport implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
var definition = new RootBeanDefinition();
definition.setBeanClass(Bird.class);
registry.registerBeanDefinition("bird", definition);
}
}
@Import(MyBeanImport.class)
@Configuration
public class BeanConfiguration {
}
refresh 解析
refresh 方法定义在 AbstractApplicationContext,用于加载或刷新配置,调用了如下 13 个方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
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();
}
}
}
prepareRefresh
设置容器状态:启动时间、active 标记,初始化属性设置,检查必备属性是否存在。
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
// Initialize any placeholder property sources in the context environment.
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
}
必备属性可以通过在 ApplicationContextInitializer 的 initialize 方法中调用 environment.setRequiredProperties()
方法添加,缺少必备属性时抛出 MissingRequiredPropertiesException 异常,SpringApplication 初始化失败。
obtainFreshBeanFactory
通知子类刷新内部的 beanFactory,设置 beanFactory 序列化 ID,获取 beanFactory(DefaultListableBeanFactory)。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
// 设置序列化 ID,可用于通过此 ID 反序列化 BeanFactory 对象
this.beanFactory.setSerializationId(getId());
}
prepareBeanFactory
设置 beanFactory 的属性:ClassLoader、PropertyEditorRegistrar、BeanPostProcessor,设置忽略的自动装配接口,注册默认环境相关的 Bean。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
}
postProcessBeanFactory
子类重写以在 beanFactory 完成创建后做进一步设置,WEB 环境中注册 ServletContextAwareProcessor,注册 WEB 环境特有的 scope:request、session、application。
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
registerWebApplicationScopes();
}
invokeBeanFactoryPostProcessors
按顺序实例化并调用所有已注册的 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor,上述注解配置方式四定义的 MyBeanRegister 在这里被调用,此方法主要作用有:
- 调用 BeanDefinitionRegistryPostProcessor 实现向容器内添加 Bean 的定义。
- 调用 BeanFactoryPostProcessor 实现向容器内 Bean 的定义添加属性。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}
registerBeanPostProcessors
按顺序实例化并注册所有 BeanPostProcessor ,但不调用。
initMessageSource
初始化国际化相关属性。
initApplicationEventMulticaster
初始化事件广播器。
onRefresh
在 WEB 环境中调用 createWebServer 方法创建 WEB 容器。
// ServletWebServerApplicationContext
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
registerListeners
添加容器内事件监听器至事件广播器中,广播早期事件。
finishBeanFactoryInitialization
初始化所有剩余的单例 Bean。
finishRefresh
初始化生命周期处理器,调用生命周期处理器的 onRefresh 方法,发布 ContextRefreshedEvent 事件。
Bean 实例化解析
BeanDefinition
一个对象在 Spring 中使用 BeanDefinition 来描述,RootBeanDefinition 是其常见实现,可以通过操作 BeanDefinition 来完成 Bean 实例化和属性注入。
自定义创建 Bean
逻辑见 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
,在 createBean 方法中调用 resolveBeforeInstantiation 方法,随后调用 applyBeanPostProcessorsBeforeInstantiation 方法,最终调用 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法,该方法在实例化之前调用,如果返回 Bean 对象,则不再执行 Bean 的默认实例化逻辑(doCreateBean 方法以及属性注入等)。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
try {
// Bean 实例化之前调用,如果返回 Bean 对象,不执行后续方法
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);
}
// 调用默认实例化方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd){
Object bean = null;
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 实现 InstantiationAwareBeanPostProcessor 自定义创建 Bean
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
Bean 实例化流程
单例 Bean 实例化入口为 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
方法,主要的方法调用如图。