写在前面的话
其实这一篇文章已经脱离了依赖循环的范畴了,上一篇文章已经解释循环依赖的解决方案了,但是还没有讲解完善,
这一篇就让我们再深入理一下吧。
在之前先一些问题进行详细的探讨。
主要探讨以下几个问题,如何将bean初始化,在什么时候初始化,如果缓存中没有bean时会怎么办?
第一个问题如何将bean初始化。
初始化bean
在bean的配置时bean中一个init-method的属性。这个属性的作用就是在bean实例化之前调用init-method指定的方法来根据用户业务进行相应的实例化。
这个方法的执行位置是在Spring程序已经执行过bean的实例化,并且进行了属性的填充,这是就会调用用户设定的初始化方法。
这也解释了在什么时候进行初始化。
源码如下:
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* 初始化给定的bean实例,应用工厂回调
* 以及初始化方法和bean后处理程序。
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
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处理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 应用前处理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 激活自定义的init方法
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()) {
// 后处理器应用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这个函数的主要目的是进行客户设定的初始化方法调用。
但是除此之外还进行了一些其他的必要工作,这里也一并进行说明了。
1.激活Aware方法
在此之前介绍一下Aware的使用
Aware使用
Spring中提供了一些Aware相关接口,比如BeanFactoryAware、ResourceLoaderAware、ApplicationContextAware等,
实现这些接口的bean在被初始化之后,可以取得一些相应的资源,、
例如实现BeanFactoryAware的bean在初始化后,Spring容器将会注入BeanFactory的实例,
而实现ApplicationContextAware的bean,在bean被初始后,将会被注入ApplicationContext的实例等。
举例说明:
1.定义普通的bean
@Component
public class Hello {
public void say(){
System.out.println("hello");
}
}
2.定义BeanFactoryAware类型的bean
@Component
public class Test implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
// 声明bean的时候Spring会自动注入BeanFactory
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void testAware(){
// 通过hello这个bean id 从beanFactory获取实例
Hello hello = (Hello) beanFactory.getBean("hello");
hello.say();
}
}
- 测试Springboot 的项目环境中测试方式如下:
可以看到控制台输出了Hello。
按照上面的方法我们可以获取Spring中的BeanFactory,并且可以根据BeanFactory获取索引的bean,以及进行相关的设置。
接下来我们回到激活Aware方法这一点上面来,也就是调用的invokeAwareMethods方法的源码。
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
不难看出就是对特殊的bean处理。
2.处理器的应用
BeanPostProcessor是Spring开放式架构中的一个必不可少的亮点,给用户权限去更改或者扩展Spring。
BeanPostProcessor使用的位置就是在initializeBean这个方法中,在调用客户自定义初始化方法前以及
自定义初始化方法后分别调用BeanPostProcessor的postProcessBeforeInitialization和
postProcessAfterInitialization方法。
3.激活自定义的init方法(invokeInitMethods)
除了init-method外,还有自定义的bean实现InitializingBean接口,并在afterPropertiesSet中实现自己的初始化业务逻辑。
init-method和afterPropertiesSet都在初始化bean的时候执行,顺序是afterPropertiesSet先执行,然后执行init-method。
/**
* Give a bean a chance to react now all its properties are set,
* and a chance to know about its owning bean factory (this object).
* This means checking whether the bean implements InitializingBean or defines
* a custom init method, and invoking the necessary callback(s) if it does.
* 给bean一个反应的机会,现在它的所有属性都设置好了,
* 并有机会了解其所属的bean工厂(此对象)。
* 这意味着检查bean是否实现了InitializingBean或定义
* 一个自定义的init方法,并调用必要的回调(s)。
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the merged bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @throws Throwable if thrown by init methods or by the invocation process
* @see #invokeCustomInitMethod
*/
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 首先会检查是否是InitializingBean,如果是就要调用afterPropertiesSet方法
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 属性初始化后处理
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 调用自定义初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
最后一个问题如果缓存中没有bean时会怎么办?
一般而言会先从缓存中去获取bean,如果缓存不存在已经加载的单例bean时,就需要从头开始bean的加载过程了
在Spring中是通过getSingleton的重载方法实现的bean的加载过程。
源码如下:
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* 返回在给定名称下注册的(原始)单例对象,
* 创建并注册一个新的,如果没有注册。
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//全局变量需要同步
synchronized (this.singletonObjects) {
//先检查对应的bean是否已经加载过,因为singleton模式其实就是复用已创建的bean
Object singletonObject = this.singletonObjects.get(beanName);
//如果为空才进行singleton的bean的初始化
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 初始化bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//加入缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
可看到,通过这一步创建bean之后,最后会将bean实例加入缓存。
上述方法使用了回调方法,目的使程序在单例的创建前后做些扩展操作。
真正获取单例bean的方法并不在此方法中,其实现逻辑是在ObjectFactory类型的实例singletonFactory中
实现的。
该方法做了一下几件事:
1.检查缓存是否已经加载过。
2.若没有加载,则记录beanName为正在加载状态。
3.加载单例前记录加载状态。
beforeSingletonCreation方法虽然里面没有任何实现,但是非常重要,
/**
* Callback before singleton creation.
* 创建单例之前的回调。
* <p>The default implementation register the singleton as currently in creation.
* @param beanName the name of the singleton about to be created
* @see #isSingletonCurrentlyInCreation
*/
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
它做了一个操作:记录加载状态。
通过this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录到缓存中,
这样便可以对循环依赖进行检测。
4.通过调用参数传入的ObjectFactory的个体Object方法实例化bean。
5.加载单例后的处理方法调用。afterSingletonCreation
和步骤3类似,当bean加载结束后需要移除缓存中对该bean的正在加载状态记录。
/**
* Callback after singleton creation.
* 创建单例之后的回调。
* 当bean加载结束后需要移除缓存中对该bean的正在加载状态记录。
* <p>The default implementation marks the singleton as not in creation anymore.
* @param beanName the name of the singleton that has been created
* @see #isSingletonCurrentlyInCreation
*/
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
6.将结果记录到缓存中并删除加载bean过程中所记录的各种辅助状态。
/**
* Add the given singleton object to the singleton cache of this factory.
* 将给定的单例对象添加到该工厂的单例缓存中。
* 将结果记录到缓存中并删除加载bean过程中所记录的各种辅助状态
* <p>To be called for eager registration of singletons.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
7.返回处理结果
至此我们也知道,并没有对bean加载的功能进行详细的了解,上面说到实现逻辑是在ObjectFactory类型的实例singletonFactory中,我们反推参数的获取,可以得到如下的代码:
sharedInstance = getSingleton(beanName, () -> {
try {
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;
}
});
ObjectFactory的核心部分其实只是调用了createBean方法,还需要深入createBean方法才能得出最终的结果。
写在后面的话
至此在上一篇文章中提到的3个问题,相信到现在都已经了答案。
但是是不是总感觉查了一点,还是不够透彻,不慌我们在最后一篇中就彻底弄清楚。
下一篇我们会介绍下spring如何从bean的实例中获取对象。