深入研究Spring-IoC:原始碼分析依賴注入
阿新 • • 發佈:2018-11-01
1.前言
對於容器建立的過程已經闡述過一遍了,下面是依賴注入的問題。Spring提供的依賴注入的方法主要由兩種:一種是通過getBean的方法;另一種是通過註解@Autowaire。
需要指出的是依賴注入的過程是使用者第一次向ioc容器索要Bean的時候開始生產的,也可以通過設定BeanDefinition的lazy-init屬性來體現例項化。
2.分析
執行程式碼:
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService" );
getBean方法實現類是AbstractBeanFactory:
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined" );
}
Object bean = beanDefinition.getBean();
if (bean == null) {
//核心程式碼
bean = doCreateBean(beanDefinition);
bean = initializeBean(bean, name);
beanDefinition.setBean(bean);
}
return bean;
}
在其中關鍵是doCreateBean(beanDefinition)方法,
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
//例項化beanDefinition
Object bean = createBeanInstance(beanDefinition);
beanDefinition.setBean(bean);
//增加屬性
applyPropertyValues(bean, beanDefinition);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}
呼叫applyPropertyValues方法:
protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
//屬性注入的核心程式碼
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getName());
}
try {
Method declaredMethod = bean.getClass().getDeclaredMethod(
"set" + propertyValue.getName().substring(0, 1).toUpperCase()
+ propertyValue.getName().substring(1), value.getClass());
declaredMethod.setAccessible(true);
declaredMethod.invoke(bean, value);
} catch (NoSuchMethodException e) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, value);
}
}
}
3.總結
依賴注入的過程中,getBean是一個起點,之後呼叫createBean方法,根據BeanDefinition定義生產Bean和屬性注入。
其中例項化bean的過程可以採用CGLIB進行。CGLIB是常用的位元組碼.class生成器類庫,提供了一些列api來提供生成和轉換Java位元組碼的功能。
在IOC容器中,提供了SimpleInstantiationStrategy類生產Bean,它提供了兩種方式,一種是BeanUtils,它是JVM的反射機制。另一種就是CGLIB的方式。