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!
推薦閱讀:
- None Found