详细的大家可以看https://blog.csdn.net/java_lyvee/article/details/101793774或者它的bilibili视频
bean的创建过程:
- spring扫描scan指定的包下添加了Component等注解的类
- 为这些类创建一个BeanDefinition的子类对象,这个子类对象包含这个类的一些基本信息如类名称、描述、构造器参数、是否需要延迟加载等等
- 将这个子类对象放到Spring的单例池(是一个map)中,
- 如果我们需要对spring进行扩展,可以让类实现BeanFactoryPostProcessor接口,如果实现了此接口,我们会在创建子类对象存放到map之后,new对象之前,会去调用扩展的方法。
比如原来的BeanDefinition子类对象中有一个属性时beanClass,这个beanClass存放的是x这个类,我们可以在此时将x换成Y,因为Y我们没有添加到包扫描中,这样我们创建出的就是Y的对象。
- 最近通过for循环获取BeanDefinition子类对象的构成的map中的子类对象,查看这个类的基本信息,进行验证,如果需要创建对象,就调用prestantiateSingletons将此类new出来,放到Spring单例池中。
源码验证过程的一部分小示例:(DefaultListableBeanFactory类中)
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || this.isAllowEagerClassLoading()) && !this.requiresEagerInitForType(mbd.getFactoryBeanName()))) {
spring对类进行扩展举例:
- 添加了Component注解的类:
@Component
public class UserServiceA {
public UserServiceA() {
System.out.println("A init ....");
}
}
- 没有添加注解的类:
public class UserServiceB {
public UserServiceB() {
System.out.println("B init ....");
}
}
- 包扫描类:
@ComponentScan("com.yhx.toali.SpringStudy")
public class ScanConfig {
}
- spring扩展类,将注入的UserSerivceA对象替换为UserServiceB对象:
@Component
public class ExtendSpring implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
GenericBeanDefinition userServiceA = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("userServiceA");
// 将注入的UserSerivceA对象替换为UserServiceB对象
userServiceA.setBeanClass(UserServiceB.class);
}
}
- 测试类:
public class GetBean {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(ScanConfig.class);
System.out.println(ac.getBean(UserServiceB.class));
}
}
- 输出结果:
问题:如何证明Spring是默认支持循环依赖的?
Spring在初始化bean的生命周期过程当中,当它把bean实例化之后,他会去进行一次判断,判断容器允不允许循环依赖,判断的属性是allowCircularReferences,这个属性默认是true,我们可以通过spring提供的api来设置这个属性。 如果这次判断成立,spring会去第四次调用后置处理器。
示例:关闭循环依赖
/*AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(ScanConfig.class);*/
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext();
ac.register(ScanConfig.class);
AbstractAutowireCapableBeanFactory beanFactory =
(AbstractAutowireCapableBeanFactory) ac.getBeanFactory();
// 关闭循环依赖
beanFactory.setAllowCircularReferences(false);
// 这个方法才是真正的初始化bean的方法,所以我们可以在这个方法调用之前,关闭循环依赖
ac.refresh();
问题:@Resource和@Autowired的区别
- 简单区别:Autowired支持类型注入,Resource支持类型和类名注入
- 深入区别:他们后置处理器的处理类不一样,CommonAnnotationBeanPostProcessor是处理Resource的,AutowiredAnnotationBeanPostProcessor是处理Autowired的。
循环依赖的解决过程(理论):
假设A中注入了B,B中注入了A。
- 第一次实例化A时,Spring会调用doGetBeam去容器中拿A,如果拿不到A,再判断A是不是在创建的过程中,如果也不在创建的过程中,会调用getSingleton方法创建A,在创建A之前,会调用beforeSingletonCreation(beanName)方法把A放到一个set集合中,表示A正在创建。如果下次再调用getSingleton方法,进入判断A是不是创建中的状态,就会判断为true。
doGetBean方法:
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 调用getSingleton判断容器中有没有或者该bean有没有再创建的过程中
Object sharedInstance = this.getSingleton(beanName);
........
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
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 (this.logger.isDebugEnabled()) {
this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 标记为创建中
this.beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = this.suppressedExceptions == null;
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet();
}
。。。。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
- 接着调用createbean方法把A创建出来(instanceWrapper = this.createBeanInstance(beanName, mbd, args);),调用构造方法,然后走A的生命周期,当生命周期走到populateBean()这个方法时,Spring会去填充A中的属性(注入),发现B需要填充,然后Spring就去getBean(B),但是此时spring容器中并没有B,因为此时只实例化了A对象。(对象并不是bean,只能是一个bean的半成品)
.....
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, () -> {
try {
// createBean调用AbstractAutowireCapableBeanFactory类中的createBean发方法
// 解咒调用doCreateBean方法
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
....
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建对象 new的过程
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable var17) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
}
mbd.postProcessed = true;
}
}
// 判断是否允许循环依赖
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
// 第四次调用后置处理器,把bean工厂放到一个以beanname为key的map工厂(第二个map)中
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
try {
// 填充当前类的属性
this.populateBean(beanName, mbd, instanceWrapper);
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
if (earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
- 此时又去实例化B(和A一样的步骤),创建B,调用构造方法,然后走B的生命周期,当生命周期走到populateBean()这个方法时,Spring又去填充B中的属性,发现A需要填充,又去容器中getBean(A),但是此时容器中并没有A的Bean,此时new出来的只是对象并不是Bean 。
- 因为每次getBean,都会先去去Spring单例池中拿,如果单例池中拿不到,再去判断对象是不是再创建的过程中,如果对象在创建的过程中,此时就从第三个缓存(earlySingletonObjects)中拿A,但是之前是将A的bean工厂放到第二个缓存中(singletonFactories),所以目前从第三个缓存拿不到A,接着进入判断,判断为true,从第二个缓存中拿到bean放到第三个缓存中,从第二个缓存中清除
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// singletonObjects --> 第一个map:单例池(Spring容器)
Object singletonObject = this.singletonObjects.get(beanName);
// 单例对象此时为空,接着判断对象是不是在创建的过程中
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
// earlySingletonObjects --> 第三个map:第三个缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//singletonFactories --> 第二个map:工厂map
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 从第二个map(缓存)中拿到bean的半成品
singletonObject = singletonFactory.getObject();
// 放到第三个缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 从第二个缓存中删除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 此时A是个半成品,然后将A填充到B中,B填充完成,成为了一个完整的Bean。
- 接着,方法会不停往前返回,一直到A填充B的地方,B此时已经有了,此时会将B填充上,整个流程基本完成。
上节中的三个map(缓存)
1.三级缓存: Map<String, Object> earlySingletonObjects = new HashMap(16);
三级缓存put了一个从二级缓存中产生出来的一个对象。防止二级缓存每次都产生对象
为什么不直接从二级缓存拿(不要三级缓存,只用原来的二级缓存工厂)?
因为性能问题,如果只用原来的二级缓存工厂,我们可能有多个循环引用比如A
,B中都引用C,如果我们只使用二级缓存,如果每次二级缓存创建都需要10s,第二次可能还是要10s,如果第一次创建完就放到三级缓存中可以节省时间提高性能。
2.二级缓存:Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
里面放的是对象的工厂对象 ,为了解决循环依赖。(利用了策略+工厂模式生成了一个合格的Bean)
为什么要存放工厂对象,为了进行AOP,对bean进行升级处理。
对象进入工厂之后,想干嘛就干嘛,可以产生你想要的自定义的代理对象,对对象进行加工。
比如循环依赖时,A中有B,B中有A,先创建A,A要注入B,B要注入A,并且B觉得A的功能不够用,此时A的工厂对象在二级缓存中,我们获取到A注入到B中,获取到的A并不是A本身,而是A的代理对象,加工之后的A 。
1.一级缓存: Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
beanName为key,单例bean为value
一级缓存,其实就是spring单例池,即Spring容器。
单例对象只会初始化一次,所以需要一个单例池来缓存。
原形就不需要缓存。
Bean生命周期回调
分为2种:
- 初始化回调
- 销毁回调
初始化回调三种方式:
- 实现InitializingBean接口,重写其中afterPropertiesSet()方法
- 在类中定义一个方法,在xml中配置init-method
- 在bean的随便一个方法上加上@PostConstruct注解
初始化回调三种方法可以同时存在,这三种方法的执行顺序:
先执行注解方式,再执行实现接口方法,最后执行xml方式。
原因:
if (mbd == null || !mbd.isSynthetic()) {
// 执行spring中的内置处理器,@PostConstruct
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
// 执行InitializingBean 初始化
// 这里时解析接口和xml方式的
this.invokeInitMethods(beanName, wrappedBean, mbd);
}
Spring中的策略模式
比如BeanPostProcessor接口,被很多类实现,每个类对同一个方法有不同的实现。
Spring在Bean的生命周期中,会调用BeanPostProcessor这个后置处理器,内部就是用策略模式,所有的后置处理器都实现了BeanPostProcessor接口,每个后置处理器对BeanPostProcessor接口中的方法都有不同的实现,有的对Bean进行了修改,有的进行了方法调用,得到Bean的所有注解信息等等。