spring-ioc
ioc
- 初始化容器阶段
- 初始化beanfactory
- 解析配置成beanDefine
- 注册bd到bf中
- 执行BeanFactoryPostProcessor
- 根据bd针对单例非懒加载bean进行实例化
- 实例化会执行bfProcessor和BeanProcessor的钩子函数
执行 BeanFactoryPostProcessor ...
执行 BeanPostProcessor-postProcessBeforeInitialization... beanName:dowJonesNewsListener
执行 BeanPostProcessor-postProcessAfterInitialization... beanName:dowJonesNewsListener
执行 BeanPostProcessor-postProcessBeforeInitialization... beanName:djNewsProvider
执行 BeanPostProcessor-postProcessAfterInitialization... beanName:djNewsProvider
执行 BeanPostProcessor-postProcessBeforeInitialization... beanName:dowJonesNewsPersister
执行 BeanPostProcessor-postProcessAfterInitialization... beanName:dowJonesNewsPersister
执行 BeanFactoryAware ...
执行 BeanPostProcessor-postProcessBeforeInitialization... beanName:ioc.spring.BeanAwareDemo#0
执行 BeanPostProcessor-postProcessAfterInitialization... beanName:ioc.spring.BeanAwareDemo#0
执行 业务方法。。。。。
123
FactoryBean 的作用主要用于一些复杂对象的初始化,比如数据库连接池
源码解读
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setAllowCircularReferences(true);
applicationContext.setConfigLocation("spring-beans.xml");
applicationContext.refresh();
FXNewsProvider newsProvider = (FXNewsProvider) applicationContext.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
核心方法是refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 记录容器的启动时间、标记“已启动”状态
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//解析配置文件成BeanDefine map集合,创建BeanFactory并存储BeanDefine,此处并未进行bean实例化
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置classLoader,设置PostProcessor,设置一些ignore依赖接口(不自动注入)
prepareBeanFactory(beanFactory);
try {
// 非重点
postProcessBeanFactory(beanFactory);
// 调用配置的BFP,配置的所有BFP都会在这个地方被执行
invokeBeanFactoryPostProcessors(beanFactory);
// 注册配置的BP到容器中,注意不会执行BP,BP只会在Bean实例化前后被调用
registerBeanPostProcessors(beanFactory);
// 初始化MessageSouce到容器中(系统国际化会用到)
initMessageSource();
// 初始化applicationEventMulticaster到容器中
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//模版方法,可以被重写,主要进行其他特殊bean的初始化操作
onRefresh();
// 注册listener 暂过
registerListeners();
// 初始化剩下的所有非懒加载的单例模式对象,重点
finishBeanFactoryInitialization(beanFactory);
// 最后一步,发布refresh完成事件,主要是调用配置的lifecycleProcessor
finishRefresh();
}
}
}
spring配置文件会有几个比较特殊bean,对应上面的几个方法,都是从map中取出注册(初始化)到容器中
- processor
- aware
- messageSource
- applicationEventMulticaster
- lifecycleProcessor
- conversionService
核心方法 finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化conversionService,这个用途可以是进行传输类型转化,比如常用的前端传日期类型到后端,可以使用他进行处理
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
......
// 防止配置被修改,进行冻结
beanFactory.freezeConfiguration();
// 重点是这个,接着深入
beanFactory.preInstantiateSingletons();
}
DefaultListableBeanFactory . preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
......
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
//AccessController.doPrivileged是特权模式,如果系统设置安全验证,会对包含的方法进行权限判断,没权限会抛出异常
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
......
else {
// 关键方法 对应到 doGetBean
getBean(beanName);
}
......
// 针对单例bean 如果实现SmartInitializingSingleton,会执行回调函数afterSingletonsInstantiated
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
AbstractBeanFactory . doGetBean 这个类十分的长,可能是spring为了做到通用,搞得很复杂
......
// 初始化依赖bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
//递归调用自身
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
.....
// 重要!!!!
if (mbd.isSingleton()) {
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;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
......
AbstractAutowireCapableBeanFactory . createBean
这部分代码比较多,简述一下吧。 主要是采用Java反射(支持CGLIB)进行类的实例化。 在实例化完成以后执行相应的BFP和Aware及init方法,destroy方法 关键代码如下
......
if (instanceWrapper == null) {
//这里实例化 Bean,这里非常关键
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
......
try {
// 负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
populateBean(beanName, mbd, instanceWrapper);
//还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口?
// 这里就是处理 bean 初始化完成后的各种回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
需要注意的是 BFP和想象的不太一样,它的before和after方法都是在实例化完成后执行。 理解设计这个的目的主要针对init方法来说的,init方法是在before和after中间执行的。
AbstractAutowireCapableBeanFactory . initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessBeforeInitialization 回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 处理 bean 中定义的 init-method,
// 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
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()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回调
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
spring循环引用问题
场景1 (单例对象构造方式注入)
<bean name="djNewsProvider" class="ioc.spring.FXNewsProvider">
<constructor-arg name="newsListener" ref="dowJonesNewsListener"/>
</bean>
<bean name="dowJonesNewsListener" class="ioc.spring.DowJonesNewsListener">
<constructor-arg name="fxNewsProvider" ref="djNewsProvider"/>
</bean>
默认情况下支持循环引用,可通过setAllowCircularReferences修改
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
// applicationContext.setAllowCircularReferences(false);
applicationContext.setConfigLocation("spring-beans.xml");
applicationContext.refresh();
FXNewsProvider newsProvider = (FXNewsProvider) applicationContext.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
抛出BeanCurrentlyInCreationException
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'djNewsProvider' defined
in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'dowJonesNewsListener' while setting
bean property 'newsListener'; nested exception is **org.springframework.beans.factory.BeanCreationException**: Error
creating bean with name 'dowJonesNewsListener' defined in class path resource [spring-beans.xml]: Cannot resolve
reference to bean 'djNewsProvider' while setting bean property 'fxNewsProvider'; nested exception is **org.springframework.beans.factory.BeanCurrentlyInCreationException**: Error creating bean
with name 'djNewsProvider': Requested bean is currently in creation: Is there an unresolvable circular reference?
场景2 (单例对象set方式注入)
<bean name="djNewsProvider" class="ioc.spring.FXNewsProvider">
<property name="newsListener" ref="dowJonesNewsListener"/>
</bean>
<bean name="dowJonesNewsListener" class="ioc.spring.DowJonesNewsListener">
<property name="fxNewsProvider" ref="djNewsProvider"/>
</bean>
默认情况下支持循环引用,可通过setAllowCircularReferences修改
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setAllowCircularReferences(false);
applicationContext.setConfigLocation("spring-beans.xml");
applicationContext.refresh();
FXNewsProvider newsProvider = (FXNewsProvider) applicationContext.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
抛出BeanCurrentlyInCreationException
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'djNewsProvider' defined
in class path resource [spring-beans.xml]: Cannot resolve reference to bean 'dowJonesNewsListener' while setting
bean property 'newsListener'; nested exception is **org.springframework.beans.factory.BeanCreationException**: Error
creating bean with name 'dowJonesNewsListener' defined in class path resource [spring-beans.xml]: Cannot resolve
reference to bean 'djNewsProvider' while setting bean property 'fxNewsProvider'; nested exception is **org.springframework.beans.factory.BeanCurrentlyInCreationException**: Error creating bean
with name 'djNewsProvider': Requested bean is currently in creation: Is there an unresolvable circular reference?
场景3 (多例对象set方式注入)
<bean name="djNewsProvider" class="ioc.spring.FXNewsProvider" scope="prototype">
<property name="newsListener" ref="dowJonesNewsListener"/>
</bean>
<bean name="dowJonesNewsListener" class="ioc.spring.DowJonesNewsListener" scope="prototype">
<property name="fxNewsProvider" ref="djNewsProvider"/>
</bean>
抛出BeanCurrentlyInCreationException
Exception in thread "main" org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'djNewsProvider' defined in class path resource [spring-beans.xml]:
Cannot resolve reference to bean 'dowJonesNewsListener' while setting bean property 'newsListener';
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dowJonesNewsListener' defined in class path resource [spring-beans.xml]:
Cannot resolve reference to bean 'djNewsProvider' while setting bean property 'fxNewsProvider'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'djNewsProvider': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
spring是如何解决循环依赖?
spring 只支持单例对象使用set属性方式注入循环依赖,构造函数注入以及多例对象是不支持的。单例对象在执行完构造函数之后,在未设置属性之前,会将实例化完成的对象缓存到early缓存中,每次zai
AbstractAutowireCapableBeanFactory.doCreateBean
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//注意看注释部分,Eagerly(early?官方注释错误) cache singletons to be able to resolve circular references 循环依赖主要通过ealy缓存解决
//allowCircularReferences 默认为true,允许循环依赖,可以配置
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 和想象的一样,early缓存发生在实例化完成之后,属性设置之前。
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
DefaultSingletonBeanRegistry.getSingleton 利用三级缓存
- singletonObjects
- earlySingletonObjects
- singletonFactories
先从so中取,取不到 判断是否是正在创建的单例bean,不是的话直接返回NULL,如果是正创建bean, 从earlySingletonObjects中取,此处表示,正创建的bean,实例化完成会加到early中,如果还取不到, 就从singletonFactories中取,如果取到了 则将结果放到early中,并从factory中移除。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
下面分析抛出BeanCurrentlyInCreationException的源头
多例对象直接抛出
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
DefaultSingletonBeanRegistry.getSingleton
......
beforeSingletonCreation(beanName);
......
afterSingletonCreation(beanName);
......
DefaultSingletonBeanRegistry.beforeSingletonCreation DefaultSingletonBeanRegistry.afterSingletonCreation
......
/** 当前正在创建的bean名称集合
存储的主要是正在实例化的bean
*/
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//每次创建单例bean之前都会检查
protected void beforeSingletonCreation(String beanName) {
//关键代码this.singletonsCurrentlyInCreation.add(beanName) 如果已经存在正创建集合中 会返回false,这时候会抛出上面所说的循环引用异常
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
......
spring循环依赖三层缓存 AbstractBeanFactory.doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
......
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
......
← mysql spring-aop→