一、 简介
1. 内容回顾
前面分析了Spring的Bean的生命周期的源码,然后分析了依赖注入源码,以及依赖注入的过程中循环依赖Spring的解决方案。在介绍Bean的生命周期中,我们并没有详细介绍Spring底层是如何真正创建Bean的,其实Spring底层创建Bean和我们new一个对象是一样的,也需要使用到构造函数,这篇文章就详细分析这一部分的源码,这样Bean的生命周期的所有相关的源码就几乎分析完了。
2. Spring推断构造方法
Spring推断构造方法的大致流程如下:
首先创建AService类:
@Component
public class AService {
@Autowired
BService bService;
//空构造方法
public AService(){
System.out.println("AService的无参构造方法");
}
//有参构造方法
public AService(BService bService){
System.out.println("AService的有参构造方法");
this.bService=bService;
}
public void test(){
System.out.println(bService);
}
}
AService有两个构造方法,一个是无参的构造方法,一个是有参的构造方法
创建BService:
@Component
public class BService {
}
然后我们测试一下:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 BoxService bean
AService aService = (AService) applicationContext.getBean("AService");
// 关闭 ApplicationContext
applicationContext.close();
}
}
由输出结果我们可以看出,在创建AService这个Bean时,默认调用了AService的无参数构造方法。现在我们把无参数的构造方法去掉,再次观察结果。
发现此时Spring调用了有参数的构造方法,此时我们再加入一个CService
@Component
public class CService {
}
然后修改AService代码
@Component
public class AService {
@Autowired
BService bService;
@Autowired
CService cService;
// //空构造方法
// public AService(){
// System.out.println("AService的无参构造方法");
// }
//有参构造方法
public AService(BService bService) {
System.out.println("AService的有参构造方法1");
this.bService = bService;
}
//有参构造方法
public AService(CService cService) {
System.out.println("AService的有参构造方法2");
this.cService = cService;
}
public AService(BService bService, CService cService){
System.out.println("AService的有参构造方法3");
this.bService=bService;
this.cService=cService;
}
public void test() {
System.out.println(bService);
}
}
再次测试
发现直接报错了,说明Spring在多个构造方法中没有推断出到底使用哪一个构造方法。
我们可以在我们需要的构造方法上加一个@Autowired
注解告诉Spring我们要使用哪一个构造方法。
@Component
public class AService {
@Autowired
BService bService;
@Autowired
CService cService;
// //空构造方法
// public AService(){
// System.out.println("AService的无参构造方法");
// }
//有参构造方法
public AService(BService bService) {
System.out.println("AService的有参构造方法1");
this.bService = bService;
}
//有参构造方法
public AService(CService cService) {
System.out.println("AService的有参构造方法2");
this.cService = cService;
}
@Autowired
public AService(BService bService, CService cService) {
System.out.println("AService的有参构造方法3");
this.bService = bService;
this.cService = cService;
}
public void test() {
System.out.println(bService);
}
}
同时也可以通过getBean方法来指定我们的构造方法,注意此时AService要改为懒加载的,如果不是懒加载AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
就默认将我们的非懒加载的Bean初始化完了,所以下面测试代码会直接报错,所以需要在AService上加一个@Lazy
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 BoxService bean
AService aService = (AService) applicationContext.getBean("AService",new CService());
// 关闭 ApplicationContext
applicationContext.close();
}
}
修改AService
public class AService {
@Autowired
BService bService;
@Autowired
CService cService;
// //空构造方法
// public AService(){
// System.out.println("AService的无参构造方法");
// }
//有参构造方法
public AService(BService bService) {
System.out.println("AService的有参构造方法1");
this.bService = bService;
}
//有参构造方法
public AService(CService cService) {
System.out.println("AService的有参构造方法2");
this.cService = cService;
}
public AService(BService bService, CService cService) {
System.out.println("AService的有参构造方法3");
this.bService = bService;
this.cService = cService;
}
public void test() {
System.out.println(bService);
}
}
现在AService并不是一个Bean,我们修改测试类
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(AService.class);
//指定创建bean时,构造方法的入参值
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new BService());
applicationContext.registerBeanDefinition("AService",beanDefinition);
applicationContext.refresh();
AService aService = (AService) applicationContext.getBean("AService");
applicationContext.close();
}
}
上面我们自己定义了一个BeanDefinition,然后注册到容器中,同样最后也可以拿到创建好的Bean
下面对上面内容总结一下:
- 默认情况使用空构造方法,或使用唯一的那一个有参的构造方法
- 如果指定了构造方法的入参值,通过getBean方法或者BeanDefinition.getConstructorArgumentValues()指定,那就用所匹配的构造方法
- 如果要Spring自己选定构造方法以及构造方法的入参值,使用
autowired="constructor
- 通过
@Autowired
注解指定了某个构造方法,但是值Spring自动来找
注意加@Autowired在构造方法或配置autowired="constructor"在xml配置文件中,这两个是有区别的,前者会指定要用那个构造方法(这个是定死的),然后spring自动找对应的参数值,后者构造方法和参数值都是Spring自己去确定的(默认是选参数最多的构造方法)。
上面介绍了多种指定创建Bean时指定构造方法的多种方式,下面我们就针对这些方式详细分析一下Spring底层时怎么做的。
二、 源码分析
上面内容都是创建Bean的内容,所以我们先进入doCreateBean方法。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 实例化bean
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建Bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 后置处理合并后的BeanDefinition
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 为了解决循环依赖提前缓存单例创建工厂
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
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));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 属性填充
populateBean(beanName, mbd, instanceWrapper);
// 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName +