Spring IOC原理原始碼解析(@Autowired原理詳解 :標識建構函式)(一 )
IOC,inversion of control 控制反轉,有時候也叫DI,dependency injection 依賴注入,是一種程式碼解耦的方式。
在一個類中定義一個屬性,正常情況下需要在此類中有對此屬性賦值的程式碼,如setter方法,或者在建構函式中賦值,因此類和屬性之間的關係已經確定下來了,類和屬性間就有了一定的耦合關係。而IOC的精髓就是解耦,類中沒有顯式的對屬性的賦值程式碼,同時屬性的實際型別和值在執行時有系統動態的賦值,Spring對IOC做了很大的擴充套件,使用者可以很靈活的控制注入的物件型別及值。
Spring內IOC的最直接體現就是@Autowired註解,最常用的方式就是表示在屬性上,Spring容器在啟動時會將容器內型別是標識了@Autowired的屬性型別或者其子類,實現類的Bean通過反射的形式賦值給此屬性,或者叫注入的此類中。
Spring中對@Autowired註解的解析是通過一個叫AutowiredAnnotationBeanPostProcessor的BeanPostProcessor(Bean的後處理器)來進行的。BeanPostProcessor負責Bean的一系列處理,例項化前後,初始化前後燈階段執行相應方法,具體方法的執行順序如下:
BeanPostPrecessors Invoke Procedure(執行流程)
1.InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation (Class<?> beanClass, String beanName);
invoke before doCreateBean(),if the method returns not null,the return Object will as the Bean, avoid invoke doCreateBean() ;
2.SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors(Class<?> beanClass, String beanName);
used to determine to use which Constructor to instance Bean;
3.MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
the Bean gets instantiated, modify the RootBeanDefinition ,such as adding PropertyValue etc. before populate Bean;
4.SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference(Object bean, String beanName);
invoke before populate Bean,used for resolve Circular Reference;
5.InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName);
invoke in populate Bean, but before fill in values,return false will break the opreation for filling values in Bean;
6.InstantiationAwareBeanPostProcessor.postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName);
invoke in populate Bean, but before fill in values,modify the PropertyValues which will be apply for the Bean,
return null will break the opreation for filling values in Bean;
7.BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName);
invoked before invokeInitMethods, modify the finally Bean instance
8.BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName);
invoked after invokeInitMethods, modify the finally Bean instance
使用者可以自己定義自己的BeanPostProcessor,將其以Bean的形式註冊到Spring容器中,Spring容器在啟動時會執行其相應方法。
AutowiredAnnotationBeanPostProcessor在Spring容器初始化時會最先執行determineCandidateConstructors方法,先看起原始碼:
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
//此方法的含義是解析Bean類裡建構函式上的@Autowired註解,如果有合適的標識了@Autowired的建構函式,
//則在例項化此Bean時會使用此建構函式,@Import和@ComponentScan得到的Bean會如此解析,
//@Bean標識方法生成的Bean不會如此
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException {
// Let's check for lookup methods here..
if (!this.lookupMethodsChecked.contains(beanName)) {
try {
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
LookupOverride override = new LookupOverride(method, lookup.value());
try {
RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);
mbd.getMethodOverrides().addOverride(override);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(beanName,
"Cannot apply @Lookup to beans without corresponding bean definition");
}
}
}
});
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
}
catch (NoClassDefFoundError err) {
throw new BeanCreationException(beanName, "Failed to introspect bean class [" + beanClass.getName() +
"] for lookup method metadata: could not find class that it depends on", err);
}
this.lookupMethodsChecked.add(beanName);
}
// Quick check on the concurrent map first, with minimal locking.
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
// Fully synchronized resolution now...
synchronized (this.candidateConstructorsCache) {
//對每個類的建構函式只解析一次,解析完會儲存結果,以備下次服用
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
rawCandidates = beanClass.getDeclaredConstructors();
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
for (Constructor<?> candidate : rawCandidates) {
//檢視建構函式上是否標識@Autowired註解,獲取註解的屬性
AnnotationAttributes ann = findAutowiredAnnotation(candidate);
if (ann == null) {
Class<?> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
try {
Constructor<?> superCtor =
userClass.getDeclaredConstructor(candidate.getParameterTypes());
//如果此建構函式是過載了父類的建構函式,則尋找父類的建構函式,檢視是否標識@Autowired註解,獲取註解的屬性
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {
// Simply proceed, no equivalent superclass constructor found...
}
}
}
//當建構函式上存在@Autowired註解
if (ann != null) {
//@Autowired預設的required = true,當有一個required = true的@Autowired標識的建構函式時,
//不能有其他的建構函式再標識@Autowired,否則會報錯
if (requiredConstructor != null) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructor: " + candidate +
". Found constructor with 'required' Autowired annotation already: " +
requiredConstructor);
}
//@Autowired的required的屬性值,true / false
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
requiredConstructor = candidate;
}
candidates.add(candidate);
}
else if (candidate.getParameterTypes().length == 0) {
defaultConstructor = candidate;
}
}
if (!candidates.isEmpty()) {
// Add default constructor to list of optional constructors, as fallback.
////當沒有建構函式標識@Autowired時,設定預設的建構函式作為額外選擇
if (requiredConstructor == null) {
if (defaultConstructor != null) {
candidates.add(defaultConstructor);
} //如果沒有預設的無參建構函式,且有@Autowired(required = false)的建構函式,則發出警告信
else if (candidates.size() == 1 && logger.isWarnEnabled()) {
logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +
"': single autowire-marked constructor flagged as optional - " +
"this constructor is effectively required since there is no " +
"default constructor to fall back to: " + candidates.get(0));
}
}
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
} //若只有一個建構函式,且沒標識@Autowired,其引數長度>0,將其作為候選者
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterTypes().length > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
} //沒有合適的建構函式
else {
candidateConstructors = new Constructor<?>[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
}
AutowiredAnnotationBeanPostProcessor篩選@Autowired標識的建構函式的程式碼就是這些,篩選出這些建構函式之後,Spring使用ConstructorResolver這個類來擇取合適的建構函式,流程如下:
- 首先對這些建構函式按修飾符優先public排序,修飾符相同再按引數的長短排序,最先解析引數最長的public修飾的建構函式,其優先順序最高.
- 對建構函式的每一個引數解析,如果每一個引數均能從Spring容器中找到合適的Bean,則此將此建構函式作為最優解,如果容器內Bean不能滿足所有引數,則解析下一個建構函式。
- 如果存在兩個引數長度相同的建構函式,且容器內Bean均能滿足引數解析,則按引數型別和Bean型別的差異性求取引數的差異權重,比如引數是介面,Bean是實現類,則差異加2,引數是集合,Bean是單個類,則轉換成集合,差異加2等等,比較兩個建構函式的差異權重大小,差異小的那個作為最優解。如果兩個差異權重相等,則丟擲含有模稜兩可的建構函式的BeanCreationException。
- 當有了最優解的建構函式後,如果下一個建構函式的引數長度等於最優解,則解析此建構函式,如果引數長度小於最優解,則不再解析,直接忽略之後的所有建構函式。
- 當得到了建構函式最優解之後,將此建構函式存入此Bean的BeanDefinition中,以備下次複用,就是說只對建構函式候選者集合解析一次,下次例項化Bean的時候可以直接得到這個最優解。
- 以上的情況是基於Spring容器例項化Bean的情況,就是例項化時不會附帶Arguments,就是不帶引數,如果是使用者自己例項化Bean時,通過BeanFactory的 Object getBean(String name, Object… args) throws BeansException; T getBean(Class requiredType, Object… args) throws BeansException;方法例項化時,按照建構函式的順序傳入例項化引數,則Spring在找合適的建構函式時會忽略之前快取的最優解,以同樣的順序解析建構函式候選者集合,看看哪些建構函式的引數適合傳入的引數,找不到合適的則跑出BeanCreationException。
以上就是@Autowired註解在建構函式上的用法的原理及流程。
重點: BeanFactory的getBean()方法獲取scope = singleton的Bean時,不會生成新的Bean物件,
在scope為request及session的生命週期內,Bean的例項化只會觸發一次,也就是說@Autowired的標識的建構函式不是每次呼叫getBean()均會觸發執行。只有scope = prototype的Bean,才會每次均執行。