Spring 源码中 Bean 的创建应该是其核心流程之一,但是这个流程也是极其复杂的,所以还是先有个整体概念,然后再分步骤解析其中的逻辑。
- Bean 创建核心方法链路
getBean
是获取容器中 bean
实例的入口方法,Spring 容器中上层调用 getBean
的入口很多,这里就不一一列举。
Bean 的创建流程非常复杂且庞大,不太好做笔记,所以本文会围绕上面的图中流程来展开记录
一、Spring 中有哪几种方式可以完成bean的实例化
1. 通过实现 InstantiationAwareBeanPostProcessor
接口来实例化
通过实现 InstantiationAwareBeanPostProcessor
接口 ,然后在postProcessBeforeInstantiation
方法中利用 cglib 代理的方式完成 Bean 的创建,该方式创建的 Bean 对象是没有被实例化的。InstantiationAwareBeanPostProcessor
接口也是BeanPostProcessor
的子接口。该案例中只是我们自己通过这种方式来模拟 Spring 容器的实现,Spring 容器内部中只有在AOP的时候才会用这种方法创建 Bean。
- 实现了
InstantiationAwareBeanPostProcessor
接口的类方法的调用关系
public class House {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class CusInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
// BeanPostProcessor 接口的方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CCCC--执行了 BeanPostProcessor 的 postProcessBeforeInitialization 方法,说明属性填充已完成");
return bean;
}
// BeanPostProcessor 接口的方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("DDDD--执行了 BeanPostProcessor 的 postProcessAfterInitialization 方法,说明属性填充已完成");
return bean;
}
/**
* 在bean实例化之后调用,即创建bean对象之前调用
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("AAAA--执行了 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法");
return null;
}
/**
* 在bean实例化之后调用,填充属性值之前调用
* (1) 该方法返回 true 时会执行 bean 对象属性填充逻辑,如果返回 false ,不执行属性填充逻辑逻辑
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("BBBB--执行了 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法");
return true;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
<?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-3.0.xsd">
<bean id="house" class="com.sff.demo.createBean.bean.House">
<property name="address" value="小县城"></property>
</bean>
<bean class="com.sff.demo.createBean.CusInstantiationAwareBeanPostProcessor"/>
</beans>
从运行结果来看,InstantiationAwareBeanPostProcessor
的方法执行时机比BeanPostProcessor
的时机更早。如下图所示:
所以此时想要完成 Bean 的实例化创建,那么只能在 InstantiationAwareBeanPostProcessor
中的 postProcessBeforeInstantiation
方法使用 cglib 动态代理来实现bean的创建。改造代码逻辑如下:
public class CusInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
// BeanPostProcessor 接口的方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CCCC--执行了 BeanPostProcessor 的 postProcessBeforeInitialization 方法,说明属性填充已完成");
return bean;
}
// BeanPostProcessor 接口的方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("DDDD--执行了 BeanPostProcessor 的 postProcessAfterInitialization 方法,说明属性填充已完成");
return bean;
}
/**
* 在bean实例化之后调用,即创建bean对象完成后调用
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("AAAA--执行了 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法");
if (!beanClass.equals(House.class)) {
return null;
}
// 在该方法中实现 cglib 代理的方式实现完成对象的创建,此时 Spring 容器在实例化 bean 时
Enhancer en = new Enhancer();
en.setSuperclass(beanClass);
// 设置回调函数
en.setCallback(new MyMethodInterceptor());
// 返回代理对象
House house = (House) en.create();
return house;
}
private class MyMethodInterceptor implements MethodInterceptor {
/**
* @param o 表示增强的对象,即实现这个接口类的一个对象
* @param method 表示要拦截的方法
* @param objects 表示被拦截的方法的参数
* @param methodProxy 表示要触发父类的方法对象
* @return
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// cglib 代理调用 invoke 和 invokeSuper 方法的实现方式是不同的
Object returnValue = methodProxy.invokeSuper(o, objects);
return returnValue;
}
}
/**
* 在bean实例化之后调用,填充属性值之前调用
* (1) 该方法返回 true 时会执行 bean 对象属性填充逻辑,如果返回 false ,不执行属性填充逻辑逻辑
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("BBBB--执行了 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法");
return true;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
从运行结果来看,此时虽然在xml文件中配置了该 bean 的 address 属性值,但是实际输出bean的属性值为NULL。说明该种方法创建的bean对象没有完成初始化操作,如果要完成初始化该怎么办?
- 在
BeanPostProcessor
的postProcessAfterInitialization
方法中自定义填充属性逻辑即可完成
// BeanPostProcessor 接口的方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("DDDD--执行了 BeanPostProcessor 的 postProcessAfterInitialization 方法,说明属性填充已完成");
if (bean instanceof House) {
House h = (House) bean;
h.setAddress("乡村");
bean = h;
}
return bean;
}
2. 通过 Supplier
来实例化
该方式其实就是 Spring 利用了 Supplier
函数式接口,然后进行回调,在回调方法中实例化你需要的 bean
- 定义创建bean的方法
public class CreateBeanBySupplier {
public static House getBean() {
House house = new House();
house.setAddress("别墅");
return house;
}
}
- 实现
BeanFactoryPostProcessor
接口
public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("house");
GenericBeanDefinition house = (GenericBeanDefinition) beanDefinition;
// 设置回调函数
house.setInstanceSupplier(CreateBeanBySupplier::getBean);
}
}
<?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-3.0.xsd">
<bean id="house" class="com.sff.demo.createBean.bean.House">
</bean>
<bean class="com.sff.demo.createBean.SupplierBeanFactoryPostProcessor"/>
</beans>
通过该方式来实例化的bean,会按照bean生命周期走完所有流程方法。如果此时你在 xml 文件里直接注入属性的话,xml 文件中的属性值会覆盖掉代码中设置的属性值
<bean id="house" class="com.sff.demo.createBean.bean.House">
<property name="address" value="小县城"></property>
</bean>
3. 通过FactoryBean
来实例化
public class HourFactoryBean implements FactoryBean<House> {
@Override
public House getObject() throws Exception {
House house = new House();
house.setAddress("西安");
return house;
}
@Override
public Class<?> getObjectType() {
return House.class;
}
}
<bean name="car" class="com.sff.demo.createBean.HourFactoryBean"></bean>
4. 通过工厂方法来实例化
// 简单工厂
public class CarFactory {
public Car getCar() {
Car car = new Car();
car.setCarName("宝马");
return car;
}
}
<!--工厂方法注入-->
<bean id="carFactory" class="com.sff.demo.bean.CarFactory"/>
<bean id="bwmCar" factory-bean="carFactory" factory-method="getCar"/>
总结: 通过 自定义的工厂方法 、FactoryBean
的 getObject()
方法、@Bean
注解方式实例化的 bean 对象走的都是 instantiateUsingFactoryMethod()
方法来统一实例化的。
5. 通过反射来实例化
除了上面几种方式实例化 bean 外,其他的都是通过反射来实例化的
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);
}
// bean 的包装类,主要用于 bean 属性类型的解析
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
二、Spring 中是如何解析 @PostConstruct 、@PreDestroy、 @Resource
、@Autowired 和 @Value
注解的?
为什么要把这把这个五个注解的解析逻辑放在一起讲?因为它们的解析入口方法都是同一个方法,只是底层通过不同的 BeanPostProcessor
来处理的。
- 该入口方法就是:
applyMergedBeanDefinitionPostProcessors()
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
可以看到该方法处理的就是 MergedBeanDefinitionPostProcessor
处理器,这个处理器是干啥呢?它是 BeanPostProcessor
的子接口,其中有三个和本文相关的实现类:CommonAnnotationBeanPostProcessor
、
InitDestroyAnnotationBeanPostProcessor
和AutowiredAnnotationBeanPostProcessor
。
MergedBeanDefinitionPostProcessor
接口中定义了 postProcessMergedBeanDefinition
方法,该方法在入口方法: applyMergedBeanDefinitionPostProcessors()
中调用。
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
}
先给结论:
CommonAnnotationBeanPostProcessor
:该处理器中完成了@Resource
注解的解析InitDestroyAnnotationBeanPostProcessor
:该处理器中完成了@PostConstruct 和 @PreDestroy
注解的解析AutowiredAnnotationBeanPostProcessor
:该处理器中完成了@Autowired 和 @Value
注解的解析
1. CommonAnnotationBeanPostProcessor
处理器
CommonAnnotationBeanPostProcessor
的 postProcessMergedBeanDefinition()
方法中调用了父类 InitDestroyAnnotationBeanPostProcessor
的 postProcessMergedBeanDefinition()
方法,在该方法中处理了 @PostConstruct
、@PreDestroy
注解。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
/**
* 该方法是在 CommonAnnotationBeanPostProcessor 对象注入容器时通过反射调用构造器时调用,此时设置了 @PostConstruct @PreDestroy 注解类型
*/
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 处理 @PostConstruct 、@PreDestroy 注解
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 处理 @Resource 注解,找出 beanType 所有被 @Resource 标记的字段和方法封装到 InjectionMetadata 中
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
2. AutowiredAnnotationBeanPostProcessor
处理器
/**
* 注解标识的方法、字段filed 转换成 InjectionMetadata 对象
* (1) InjectionMetadata 这个类非常重要,到了此处 @Autowired 注解含义已经没有了,完全被解析成 InjectionMetadata 这个元数据对象
* (2) InjectionMetadata 持有 targetClass、Collection<InjectedElement> injectedElements 等两个重要属性
* (3) 其中 InjectedElement 这个抽象类最重要的两个实现为:AutowiredFieldElement 和 AutowiredMethodElement
*/
private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
// 设置该处理器能够解析的注解类型
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
}
/**
* (1) 解析@Autowired @Value 注解
* (2) 把注解信息转换为 InjectionMetadata 然后缓存到上面的 injectionMetadataCache 里面
*/
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
以上 BeanPostProcessor
在解析 @PostConstruct 、@PreDestroy、 @Resource
、@Autowired 和 @Value
时,最终都是将解析结果封装成了 InjectionMetadata
对象
public class InjectionMetadata {
private final Class<?> targetClass;
private final Collection<InjectedElement> injectedElements;
private volatile Set<InjectedElement> checkedElements;
// 省略部分代码 ...
}
在后续流程当中又会将 InjectionMetadata
解析,然后赋值给对应 bean 的属性上,该操作发生在 populateBean()
方法中。
三、Spring 中 Bean 的属性填充 populateBean()
方法
四、Spring 中 Bean 属性填充完成后执行 initializeBean()
方法
该方法的主要功能是:依次调用 Aware
接口相关方法、BeanPostProcessor
前置处理器、init-method
、调 BeanPostProcessor
后置处理器
(1) 为什么这里只调用了 BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
三个接口的方法?
在 obtainFreshBeanFactory()
获取容器对象 BeanFactory
时调用了构造方法 AbstractAutowireCapableBeanFactory()
中对该三个 Aware
接口进行了忽略设置,所以才会在 initializeBean()
中对这三个接口方法进行单独调用。
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
剩下的一些 Aware
接口会在 BeanPostProcessor
的 postProcessBeforeInitialization()
方法中设置到容器中去
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
- Aware 接口到底有什么用?
当对 Sprig 容器创建的 bean 对象在进行一些逻辑操作时,需要使用 Spring 容器的其他对象,此时就可以将该 bean 对象标记成 Aware 接口的实现类,比如实际开发中经常使用的 ApplicationContextAware 接口
五、Spring 中 Bean 的生命周期是什么?
在问题一中所说的bean的几种创建方式,其实就是生命周期中 bean实例化 的具体实现方式,这张图只是简单的描述了 bean 生命周期的脉络,下面这张图将详细的描述每个环境具体的操作: