【走近Spring】為脫離Spring IOC容器管理的Bean賦能【依賴注入】的能力,並分析原理(藉助AutowireCapableBeanFactory賦能)
不可否認的是,把Bean交給Spring管理,確實極其的方便,優點一大把,並且還幾乎沒有啥缺點。這也就是為何咱們一言不合就把Bean扔給Spring的原因。(在Spring的技術棧裡這麼做,完全沒有問題)
然而,就Spring框架本身而言。它的強大的依賴注入,不僅僅能給自家的Bean使用,還能賦能給容器之外的Bean,快速的把需要注入的物件給它裝配好。
本來我也一直以為你想用Spring的依賴注入功能,就得交給Spring容器進行管理。
AutowireCapableBeanFactory 的解釋
* Extension of the {@link org.springframework.beans.factory.BeanFactory} * interface to be implemented by bean factories that are capable of * autowiring, provided that they want to expose this functionality for * existing bean instances.
AutowireCapableBeanFactory在BeanFactory基礎上實現了對存在例項的管理,可以使用這個介面整合其它框架,捆綁並填充並不由Spring管理生命週期並已存在的例項。像整合WebWork的Actions 和Tapestry Page就很實用。
public interface AutowireCapableBeanFactory extends BeanFactory { int AUTOWIRE_NO = 0; int AUTOWIRE_BY_NAME = 1; int AUTOWIRE_BY_TYPE = 2; int AUTOWIRE_CONSTRUCTOR = 3; @Deprecated int AUTOWIRE_AUTODETECT = 4; // 注意這個CreateBean和下面的CrateBean的不同 //JavaDoc:It does <i>not</> imply traditional by-name or by-type autowiring of properties; // 也就是說它只管給你建立Bean,但是不管給你根據Name或者Type進行注入哦 // 當然,你可以顯示在對應屬性上指定@Autowired註解,讓他也可以達到相同的效果 <T> T createBean(Class<T> beanClass) throws BeansException; void autowireBean(Object existingBean) throws BeansException; Object configureBean(Object existingBean, String beanName) throws BeansException; Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException; Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException; void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException; void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException; Object initializeBean(Object existingBean, String beanName) throws BeansException; Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException; Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException; void destroyBean(Object existingBean); <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException; @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException; @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException; }
以createBean() 方法為例
// 準備一個Child類 @Getter @Setter public class Child { // 注意:這裡並沒有@Autowired註解的 private HelloService helloService; private String name; private Integer age; } public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class); // ApplicationContext裡面是持久AutowireCapableBeanFactory這個工具的,它真實的實現類一般都是:DefaultListableBeanFactory AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory(); // 我把Child的建立過程都交給Bean工廠去幫我們處理,自己連new都不需要了 (createBean方法執行多次,就會建立多個child例項) Child child = (Child) autowireCapableBeanFactory.createBean(Child.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); //簡直殘暴,沒有@Autowired註解都給注入進來了~~~ 至於為什麼,看看下面的分析,你就知道了 System.out.println(child.getHelloService()); //com.fsx.service.HelloServiceImpl@6a78afa0 // 丟擲異常 No qualifying bean of type 'com.fsx.bean.Child' available // 能佐證:我們的Bean並沒交給Spring容器管理,它只是幫我們建立好了,並把對應屬性注入進去了 Child bean = applicationContext.getBean(Child.class); System.out.println(bean); }
看到這個現象有沒有很驚喜,我們哪怕不是Spring去管理的物件,都能夠依賴注入進來容器內的物件,並且連@Autowired註解都不需要。所以更別談Spring內部的容器,並且還標註了註解的,那就應該更容易去實現了
以createBean() 方法為例的原始碼分析
AbstractAutowireCapableBeanFactory#createBean:
@Override
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
// 這裡看到了,採用的不是單例,而是prototype
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
// For the nullability warning, see the elaboration in AbstractBeanFactory.doGetBean;
// in short: This is never going to be null unless user-declared code enforces null.
// doc說得很明白,這裡返回值永遠不可能為null。除非呼叫者強制return null
// 注意的是:這裡BeanName就是beanClass.getName()
return createBean(beanClass.getName(), bd, null);
}
// 最終都呼叫到了下面這個createBean方法。它也是AbstractBeanFactory提供的一個抽象方法
// 最終也由AbstractAutowireCapableBeanFactory去實現的。 我們熟悉的doGetBean()方法,最終也是呼叫它來建立例項物件 只是doGetBean()把單例物件都快取起來了
// 這個方法很單純:建立一個例項,然後初始化他(給屬性們賦值),然後return出去即可
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 解析一些@lookup註解之類的 忽略
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 這個之前都解釋過了,就不解釋了。若BeanPostProcessors 產生了一個代理物件,就不需要我去建立了,就不繼續往下走了(AOP都走這裡)
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 重點來了。它是本類的一個protected方法,專門用於處理建立Bean的過程(包括屬性賦值之類的)
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
這裡再看看doCreateBean吧,因為之前有講過這個方法,這裡就只看核心步驟。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args){
BeanWrapper instanceWrapper = null;
...
//createBeanInstance 是重點(都是返回一個BeanWrapper) 它也是本類的一個protected方法
instanceWrapper = createBeanInstance(beanName, mbd, args);
// Bean已經例項化好了,準備初始化吧
...
// 執行MergedBeanDefinitionPostProcessor
// 處理迴圈引用,現在若我們Bean不在容器裡,肯定是不存在迴圈引用的(但是我依賴的Bean可能還沒建立是真的,也是這裡來處理的)
...
// 給Bean例項的各個屬性進行賦值 比如呼叫InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation、給屬性注入值(並不依賴於@Autowired註解)
// 執行InstantiationAwareBeanPostProcessor#postProcessPropertyValues等等
populateBean(beanName, mbd, instanceWrapper);
// 初始化Bean 執行一些初始化方法init @PostContruct方法等等
//BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization等等
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
綜上可以看出,目前最重要的三個步驟為doCreateBean裡面的:createBeanInstance、populateBean、initializeBean,都在AbstractAutowireCapableBeanFactory這裡
createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 如果不為null,並且還不是public的訪問許可權 並且還nonPublicAccessAllowed為false 那就拋異常吧
// 題外話:nonPublicAccessAllowed為true的情況下(預設值),即使你不是public的也ok
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 你可以自己通過Supplier來建立Bean,最終交給obtainFromSupplier包裝成BeanWrapper
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//通過工廠方法建立 支援工廠方法方式建立Bean
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
//一個類可能有多個構造器,所以Spring得根據引數個數、型別確定需要呼叫的構造器
//在使用構造器建立例項後,Spring會將解析過後確定下來的構造器或工廠方法儲存在快取中,避免再次建立相同bean時再次解析
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 首次進入,resolved為false。
// 說一下:ConstructorResolver,就是找到合適的構造器給你去例項化一個Bean(會結合Spring容器進行一起解析)
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Need to determine the constructor...
// 執行BeanPostProcesso#determineCandidateConstructors 自己去決定使用哪個構造器,可能會返回一批構造器喲
// 這裡我們很熟悉的`AutowiredAnnotationBeanPostProcessor`就實現了這個方法,可以智慧去找出一個合適的構造器.
// 這裡需要注意了,因為我們的Child的屬性HelloService裡並沒有書寫@Autowired屬性,所以這裡最終的返回結果是null================這個需要注意Spring的處理(空構造就不用交給autowireConstructor處理了,自己直接new吧)
// 需要注意的是:若我們自己寫了一個構造 public Child(HelloService helloService) { this.helloService = helloService; } 那麼它就會拿到,然後走下面讓Spring執行構造器的注入的
// 旁白:如果你只有空構造,那就直接instantiateBean,否則會自動去走Spring的構造器注入的邏輯
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
// 所以我們當前的Child,只有空構造器,所以就只能走這裡啦
// 這個方法的邏輯比較簡單,我就不貼了。主要是用InstantiationStrategy策略器進行例項化,至於它是什麼東東?文末的時候我會解釋的
return instantiateBean(beanName, mbd);
}
該方法執行完成之後,我們物件就被建立了,但僅僅還只是建立好哦。下面繼續看:
populateBean: populate:居住於; 生活於; 大致意思就是給Bean的各個屬性賦值
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
// 因為已經例項化了,物件已經建立了,所以這裡立馬執行了InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation方法
// 單反只有其中一個返回了false,相當於告訴容器我都處理好了,那麼後面的賦值操作就Spring容器就不再處理了
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
//以物件的方式儲存健值對,比儲存在map會更加靈活
//PropertyValues 是用來管理PropertyValue的 一般情況下為null
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 那麼接下來,就開始幹正事了~~~~
// 這裡需要注意的是:我們知道上面我們自己傳進來的是byType,所以這個的if是能夠進來的,最終能夠定位autowireByType讓它去實現注入功能。
//所以我們的helloService欄位要不要@Autowired要不要無所謂(要了也只是重複操作而已,但是我建議顯示的指明吧)
//但是被Spring掃描Scan管理的Bean們(或者其餘Bean),如果你想要給他欄位注入屬性值,必須必須使用@Autowired註解,從而交給後置處理器AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues這個方法去處理
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 按型別自動裝配。一般都會走這裡,通過型別的匹配,來給屬性賦值,實現注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
// 它的步驟相對簡單:顯示BeanUtils.getWriteMethodParameter(pd)拿到set方法(所以,這裡需要注意,若沒有set方法,這裡是注入不進去的,這個沒@Autowired強大)
// 然後去解析去容器裡面找對應的依賴,也是resolveDependency方法(最終由DefaultListableBeanFactory去實現的)
// 這裡需要注意:注入的時候isSimpleProperty不會被注入的(包括基本資料型別、Integer、Long。。。
//甚至還包括Enum、CharSequence(顯然就包含了Spring)、Number、Date、URI、URL、Locale、Class等等)
// 但是,但是,但是標註@Autowired是能夠注入的哦,哪怕是String、Integer等等
// 標註了@Autowired,沒有找到反倒為報錯 No qualifying bean of type 'java.lang.String' 。。。注意這些區別
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
// 開始執行InstantiationAwareBeanPostProcessor#postProcessPropertyValues
// 這裡主要施工的又是我們大名鼎鼎的AutowiredAnnotationBeanPostProcessor它了,他會根據所有標註有@Autpwired註解地方,執行注入(非常重要)
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//applyPropertyValues和PropertyValues密切相關,在後面相關專題在詳細講解 會回到這裡的,持續關注~
// 作用:Apply the given property values, resolving any runtime references
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
至此,一個Bean的例項化、初始化操作可以完成了一大部分了(各欄位、屬性的賦值也都已經ok了~),那麼還剩下一些收尾工作:比如init方法、post-construct方法之類的,就交給
initializeBean:初始化Bean(呼叫一些初始化方法)
- invokeAwareMethods:執行一些感知介面Aware的注入