Spring Bean實例的創建及構造器的挑選

一、舉個栗子

public class BeanServiceImpl implements BeanService {
}
@Configuration
public class ConfigurationBean {

    @Bean
    public BeanService beanService() {
        BeanServiceImpl beanService = new BeanServiceImpl();
        System.out.println("beanService: " + beanService);
        return beanService;
    }

    @Bean
    //@Bean 如果不知道name,默認bean的name為方法名,下面等同於@Bean("beanService1")
    public BeanService beanService1() {
        BeanServiceImpl beanService1 = new BeanServiceImpl();
        System.out.println("beanService1: " + beanService1);
        return beanService1;
    }
}
@Component
public class SetterBean {

    private BeanService bs;

    public SetterBean(BeanService beanService) {
        bs = beanService;
        System.out.println("有參構造:" + bs);
    }
}

二、創建實例的方式

  • 通過Supplier的回調方法去創建
  • 通過工廠方法去創建通過
  • 反射構造器去創建

絕大部分是通過反射構造器去創建,詳情源碼見AbstractAutowireCapableBeanFactory.doCreateBean中的createBeanInstance方法

三、反射構造器結論現象

3.1 沒有有參構造器

如果沒有有參構造器,默認使用無參的構造方法反射創建實例,詳情見createBeanInstance – instantiateBean方法

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		... ... 
		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

3.2 有唯一的有參構造器

如果有唯一有參構造器,並且參數能在Spring容器裡找到,則通過該有參構造器反射創建
    詳情見createBeanInstance – autowireConstructor方法

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		... ...
		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}
		... ...
	}

如果參數不能在Spring容器中找到,就會報NoUniqueBeanDefinitionException異常

3.3 有多個有參構造器,不指定構造器

有多個有參構造器,Spring在創建Bean實例時,就不知道用哪個構造器去創建,就會報如下異常:
  BeanInstantiationException: Failed to instantiate [XXX]: No default constructor found;

@Component
public class SetterBean {

    private BeanService bs;

    public SetterBean(BeanService beanService) {
        bs = beanService;
        System.out.println("有參構造:" + bs);
    }

	//@Autowired
    public SetterBean(BeanService beanService, BeanService beanService1) {
        bs = beanService;
        System.out.println("有參構造:" + bs + "--------" + beanService1);
    }
}

3.4 有多個有參構造器,指定有參構造

可以通過@Autowired來指定有參構造來創建實例

像3.2 中,把@Autowired註釋打開,就會使用該有參構造創建實例,啟動就不會報異常,

四、createBeanInstance功能簡介

這個方法主要是挑選構造器,然後創建實例的

  • 依次判斷使用哪種方式創建實例
  • 有參構造是否已經解析過,解析過就從緩存中拿解析過的構造器去創建
  • 沒有解析緩存過,則通過後置處理器去獲取構造器,參數如果需要註入,則autowireConstructor去註入參數,然後創建實例
  • 都不符合的話就拿默認的無參構造器去創建實例

到此這篇關於Spring Bean實例的創建及構造器的挑選的文章就介紹到這瞭,更多相關Bean實例創建及構造器挑選內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!