1. 程式人生 > 其它 >Spring原始碼-getBean獲取bean例項

Spring原始碼-getBean獲取bean例項

技術標籤:Springspring原始碼iocjava

例項化Bean

單例bean,並且lazy-init為false(預設是false),則 ApplicationContext在重新整理的時候就例項化該Bean,並且將例項化的Bean放到快取中,下次再使用該Bean的時候, 直接從這個快取中獲取;如果單例bean是懶載入的,即lazy-init為true,則在第一次getBean獲取該Bean的時候進行例項化,並放入快取;scope是prototype的多例bean,每次使用獲取Bean的時候都會進行例項化

<bean id="" class="
"
scope="作用域"/>
1. singleton: 單例 ,在Spring IoC容器中僅存在一個Bean例項 (預設的scope) 2. prototype: 多例 ,每次從容器中呼叫Bean時,都返回一個新的例項,即每次呼叫getBean() 3. request: 用於web開發,將Bean放入request範圍 , 在同一個request 獲得同一個Bean 4. session: 用於web開發,將Bean 放入Session範圍,在同一個Session 獲得同一個Bean

spring容器預設載入bean為非延遲載入,在容器重新整理階段就會例項化bean物件,設定為延遲載入則當類首次被載入時才會初始化例項,所有bean的例項化都是通過getBean去實現

<!--當前xml中所有的bean-->
<beans default-lazy-init="default | false | true">
<!--指定的bean-->
<bean lazy-init="default | false | true">

使用註解方式

@Lazy
public class Bean {}

總結所有bean的生命週期:單例且非延遲載入的bean跟隨容器重新整理完成例項初始化,之後訪問例項從快取中獲取;單例延遲載入的bean在首次訪問時通過getBean完成例項化,之後訪問從快取中獲取;

Bean例項化的方式

無引數構造器例項化

<bean id="super" name="a1,a2,a3" class="cn.mywork.spring.Super" lazy-init="true"/>

靜態工廠方法例項化

//factory-method找到工廠類的靜態方法
<bean id="student" class="cn.mywork.spring.StaticFactory" factory-method="getStu"/>

//配置靜態工廠類
public class StaticFactory {
    //通過配置檔案找到靜態方法,返回物件為建立的bean
    public static Student getStu(){
        return new Student();
    }
}

ApplicationContext context;
Student student = context.getBean("student", Student.class);

例項工廠

//先將工廠bean交給容器管理
<bean id="instanceFactory" name="fc" class="cn.mywork.wms.spring.InstanceFactory"/>
//factory-bean只能是初始化好的bean物件,通過bean工廠物件,獲取例項方法初始化bean
<bean id="student" factory-bean="fc" factory-method="getStu"/>

實現FactoryBean介面,通過getObject方法返回目標例項

//實現getObject方法
public class InstanceFactory implements FactoryBean<Student>{
    @Override
    public Student getObject() throws Exception {
        return new Student();
    }
    @Override
    public Class<?> getObjectType() {
        return null;
    }
    @Override
    public boolean isSingleton() {
        return false;
    }
}

<bean id="student" class="cn.mywork.spring.InstanceFactory"/>

註解的方式

//註解對應的配置解析
<bean id="super" class="cn.mywork.wms.spring.Super" init-method="init" destroy-method="destory" scope="prototype">
    <!--注入的屬性-->
    <property name="sub" ref="sub"/>
</bean>
<bean id="sub" class="cn.mywork.wms.spring.Sub"/>

//預設的為簡化的類名,Xml裡也同於bean標籤的id值
@Component("super")
//作用域:非單例
@Scope("prototype")
public class Super {
    private String name;
    //注入Sub初始化的例項
    @Autowired
    private Sub sub;
    //初始化的方法,init-method="init"
    @PostConstruct
    public void init(){
    }
    //銷燬的方法,destroy-method="destory"
    @PreDestroy
    public void destory(){
    }
}

自定義BeanFactory工廠

public class BeanFactoryDemo {
    //key為id,value為全限定名
    private static Map<String,String> beanMap = new HashMap<>();
    //bean快取,延遲載入bean時,genBean之後將bean放入快取
    private static Map<String,Object> cacheMap = new HashMap<>();

    //解析xml配置檔案
    static {
        try {
            //getClassLoader().getResourceAsStream是載入resources資源路徑下的配置檔案
            InputStream resource = BeanFactoryDemo.class.getClassLoader().getResourceAsStream("spring.xml");
            initBeanMap(resource);
        }catch (Exception e){}
    }

    private static void initBeanMap(InputStream resource) throws Exception {
        SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
        saxParser.parse(resource,new DefaultHandler(){
            //解析後的標籤名
            private String tagName;
            @Override
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                this.tagName = qName;
                //獲取標籤內容
                if ("bean".equals(tagName)){
                    //獲取id的值
                    String id = attributes.getValue("id");
                    //獲取bean的全限定名
                    String beanClassName = attributes.getValue("class");
                    beanMap.put(id,beanClassName);
                }
            }
            @Override
            public void endElement(String uri, String localName, String qName) throws SAXException {
                tagName = null;
            }
        });
    }

    //獲取bean例項的方法,延遲載入方式
    public static  <T> T getBean(String id,Class<T> beanClass) throws Exception{
        //只有map中存在的key值才會繼續處理
        if (beanMap.containsKey(id)){
            //再判斷快取中是否有該bean
            if (cacheMap.containsKey(id)){
                return (T) cacheMap.get(id);
            }
            String beanClassName = beanMap.get(id);
            //載入全限定名,通過反射機制建立bean
            Object instance = Class.forName(beanClassName).newInstance();
            //判斷是否為beanClass型別的例項
            if (beanClass.isInstance(instance)){
                cacheMap.put(id,instance);
                return (T) instance;
            }
        }
        return null;
    }
}

Student student = BeanFactoryDemo.getBean("student", Student.class);

getBean

refresh執行到finishBeanFactoryInitialization時才開始例項化非延遲載入的bean,主要看其中的preInstantiateSingletons方法

public void preInstantiateSingletons() throws BeansException {
    //所有的需要例項化的beanName都在beanDefinitionNames,包括 Aspectj的, 通過註解標識的
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    for (String beanName : beanNames) {
        //合併父類BeanDefinition
        //MergedBeanDefinition合併bean定義,XML 配置來註冊 bean,會被封裝成GenericBeanDefinition;使用註解的方式來註冊 bean,會被封裝成 ScannedGenericBeanDefinition,最終統一轉換成 RootBeanDefinition處理
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        //非抽象,單例,非懶載入三個條件
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            //是 FactoryBean 型別的物件則加上&
            //判斷是factoryBean還是普通bean,實現FactoryBean介面的getObject()方法可以定義建立例項物件,比如很多中介軟體的就是通過這種方式實現
            if (isFactoryBean(beanName)) {
                bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                ...
            }
            else {
                // 進入到doGetBean執行例項化bean
                bean = getBean(beanName);
            }
        }
    }
}    

容器初始化完成還是在初始化之後動態獲取bean都會訪問beanFacroty.getBean()方法,進入這個方法發現有很多分支去獲取bean,如果不是首次獲取bean則直接getSingleton()先從快取中獲取

protected <T> T doGetBean(String name, Class<T> requiredType,Object[] args, boolean typeCheckOnly) throws BeansException {
    //去掉FactoryBean的字首“&”,解析別名返回namespace的beanName
    String beanName = this.transformedBeanName(name);
    //獲取快取中的bean,不涉及建立新的bean例項和解決迴圈依賴
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    //快取中如果能獲取到
    if (sharedInstance != null && args == null) {
        //普通bean直接返回例項,factoryBean繼續處理
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
        //和singletonsCurrentlyInCreation類似存放正在建立的Prototype例項
        //迴圈依賴校驗:當前原型例項池中有正在建立的物件了,說明這個物件是個原型物件,並且當前執行緒中這個物件已經處於建立中了,會造成迴圈依賴
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }	
        BeanFactory parentBeanFactory = this.getParentBeanFactory();
        //當前BeanFactory中的beanDefinitionMap找不到當前Bean,則從parentBeanFactory獲取
        if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
            //解析別名和去掉FactoryBean的字首
            String nameToLookup = this.originalBeanName(name);
            //使用父類的doGetBean方法例項化bean
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }
            ...
        }
        //型別檢測預設為false,將beanName新增到alreadyCreated快取
        if (!typeCheckOnly) {
            this.markBeanAsCreated(beanName);
        }
        //RootBeanDefinition可以理解為一個沒有parent的獨立BeanDefinition
        //Map<String, RootBeanDefinition> mergedBeanDefinitions
        //如果mergedBeanDefinitions沒有父類定義就是BeanDefinition本身
        RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
        //檢查是抽象類則拋異常
        this.checkMergedBeanDefinition(mbd, beanName, args);
        //獲取所有當前bean的依賴,需要在依賴建立之後才能進行例項建立
        //@DependsOn這個熟悉的註解:需要依賴另一個bean的例項建立
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
            for (String dep : dependsOn) {
                // 檢查是否依賴於beanName,即存在迴圈依賴
                if (isDependent(beanName, dep)) {
                    throw new BeanCreationException();
                }
                //將dep和beanName的依賴關係註冊到dependentBeanMap中
                registerDependentBean(dep, beanName);
                //先例項化依賴的Bean
                getBean(dep);
            }
            //例項化不同的scope域的Bean
            if (mbd.isSingleton()) {
                //過載方法
                //getSingleton(String beanName, ObjectFactory<?> singletonFactory)
                sharedInstance = this.getSingleton(beanName, () -> {
                    //singletonFactory.getObject()方法最終執行的是createBean()方法
                    try {
                        return this.createBean(beanName, mbd, args);
                    } catch (BeansException var5) {
                        this.destroySingleton(beanName);
                        throw var5;
                    }
                });
                //跟上面一樣不是factoryBean則返回普通的例項物件
                bean = this.getObjectForBeanInstance(sharedInstance,name,beanName, mbd);
            } else if (mbd.isPrototype()) {
                //scope為prototype的bean建立
                var11 = null;
                Object prototypeInstance;
                try {
                    //新增到快取prototypesCurrentlyInCreation中
                    this.beforePrototypeCreation(beanName);
                    //建立例項
                    prototypeInstance = this.createBean(beanName, mbd, args);
                } finally {
                    //移除prototypesCurrentlyInCreation中的快取
                    this.afterPrototypeCreation(beanName);
                }
                //普通Bean直接返回
                bean=this.getObjectForBeanInstance(prototypeInstance,name,beanName, mbd);
            } else {
                //其他scope的bean建立
                String scopeName = mbd.getScope();
                Scope scope = (Scope)this.scopes.get(scopeName);
                //實現的也是ObjectFactory
                Object scopedInstance = scope.get(beanName, () -> {
                    //通過getObject方法呼叫,和prototype建立bean例項一致
                    this.beforePrototypeCreation(beanName);
                    Object var4;
                    try {
                        var4 = this.createBean(beanName, mbd, args);
                    } finally {
                        this.afterPrototypeCreation(beanName);
                    }
                    return var4;
                });
                bean=this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
        }
    }
}...

factoryBean

回到doGetBean()方法,如果獲取到快取則繼續進入getObjectForBeanInstance()交給factoryBean處理

//bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    //表示name以“&”為字首但不是factoryBean則拋異常
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        ...
    //不是factoryBean則直接返回
    } else if (!(beanInstance instanceof FactoryBean)) {
        return beanInstance;
    } else {
        //快取中拿到的是一個factoryBean
        Object object = null;
        if (mbd != null) {
            //標註這個beanDefinition為factoryBean
            mbd.isFactoryBean = true;
        } else {
            //入參mbd為null,所以需要從factoryBeanObjectCache快取拿到例項
            //Map<String, Object> factoryBeanObjectCache 用於快取factoryBean
            object = this.getCachedObjectForFactoryBean(beanName);
        }
		//快取中也沒有
        if (object == null) {
            FactoryBean<?> factory = (FactoryBean)beanInstance;
            //從beanDefinitionMap註冊的快取中找到beanDefinition
            if (mbd == null && this.containsBeanDefinition(beanName)) {
                //獲取合併(父容器)後的RootBeanDefinition
                mbd = this.getMergedLocalBeanDefinition(beanName);
            }
			//mbd是否是合成的,一般為false
            boolean synthetic = mbd != null && mbd.isSynthetic();
            //使用factory去例項化bean
            object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }
}

factoryBean是一個特殊的bean,實現FactoryBean介面,factoryBean在被初始化時會呼叫其getObject()方法建立應用的bean

//注入一個factoryBean
@Component
public class MyFactoryBean implements FactoryBean<HahaBean> {
    @Override
    public HahaBean getObject() throws Exception {
        //比如通過getBean(MyFactoryBean.class)則會返回hahaBean例項
        return new HahaBean();
    }

    @Override
    public Class<?> getObjectType() {
        return HahaBean.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

//getBean()會通過doGetBean方法獲取bean例項
public class SingleManApp {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(StartUp.class);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        HahaBean myFactoryBean = (HahaBean) beanFactory.getBean("myFactoryBean");
        myFactoryBean.test();
    }
}
@SpringBootApplication
public class StartUp {
}

//最終返回的例項
public class HahaBean {
    public void test(){
        System.out.println("hahabean");
    }
}

dependsOn

Spring提供比如@DependsOn/depends-on用於控制bean初始化順序,為了便於理解就不以’依賴’表示bean的關係,而是從邏輯上出發,A depends-on B,A的例項化需要B,則B優先於A進行例項化

// 檢查是否存在類似於A depondson B,而B depends-on A 的情況
if (isDependent(beanName, dep)) {
    throw new BeanCreationException();
}
//將dep和beanName的depends-on關係註冊到dependentBeanMap中
registerDependentBean(dep, beanName);
//先例項化當前bean depends-on的Bean
getBean(dep);


首先判斷是否存在迴圈depends-on,保證不存在死迴圈問題,比如A dep B,B dep C,C dep A

//dependentBeanMap存放的是depends-on當前bean的例項集合
Map<String, Set<String>> dependentBeanMap;
//dependenciesForBeanMap存放當前優先於當前bean初始化的
Map<String, Set<String>> dependenciesForBeanMap;

//alreadySeen預設為null表示還沒有檢查過
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    //表示已經檢查過了
    if (alreadySeen != null && ((Set)alreadySeen).contains(beanName)) {
        return false;
    } else {
        //如果是別名則解析別名
        String canonicalName = this.canonicalName(beanName);
        //dependentBeanMap這個集合存放的bean應該是在當前bean例項化之後才進行初始化
        Set<String> dependentBeans = (Set)this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
            return false;
            //但是dependentBeanName應該優先例項化的bean卻在dependentBeans中這就會造成死迴圈
        } else if (dependentBeans.contains(dependentBeanName)) {
            return true;
        //這一步就是徹底找到 A - B,B - C,C - D,D - A 這種隔層 depends-on
        } else {
            Iterator var6 = dependentBeans.iterator();
            String transitiveDependency;
            do {
                if (!var6.hasNext()) {
                    return false;
                }
                transitiveDependency = (String)var6.next();
                if (alreadySeen == null) {
                    alreadySeen = new HashSet();
                }
                ((Set)alreadySeen).add(beanName);
            } while(!this.isDependent(transitiveDependency, dependentBeanName, (Set)alreadySeen));
            return true;
        }
    }
}


registerDependentBean:在例項化優先的bean例項之前還需要將相互順序關係進行維護

//注意入參registerDependentBean(dep, beanName),實際deponds-on的bean位置換成了beanName
//為了方便理解還是按照依賴順序將首先例項化的稱為A(beanName),dependentBeanName稱為B
public void registerDependentBean(String beanName, String dependentBeanName) {
    String canonicalName = this.canonicalName(beanName);
    // depends-on Bean的對映集合
    Map var4 = this.dependentBeanMap;
    //depends-on A的集合(順序在A之後)
    Set dependenciesForBean;
    synchronized(this.dependentBeanMap) {
    	//java8新方法computeIfAbsent方法用來計算給定key,返回value對映值。如果,key並沒有對映到一個值,或者對映到null,那麼,就用這個value值放到這個hashmap中
    	//獲取deponds-on A的集合
        dependenciesForBean = (Set)this.dependentBeanMap
        	.computeIfAbsent(canonicalName, (k) -> {
            	return new LinkedHashSet(8);
        });
        //將B維護到deponds-on A的集合
        if (!dependenciesForBean.add(dependentBeanName)) {
            return;
        }
    }
    //Bean depends-on的集合對映
    var4 = this.dependenciesForBeanMap;
    synchronized(this.dependenciesForBeanMap) {
    	//獲取B depends-on的集合,並將A維護進去
        dependenciesForBean = (Set)this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, (k) -> {
            return new LinkedHashSet(8);
        });
        dependenciesForBean.add(canonicalName);
    }
}


getSingleton

單例bean的例項化流程

1.解析別名(如果有)獲取bean的名字
2.如果scope為sigleton則從快取中查詢是否有這個bean,否則跳過
3.首次獲取bean通過getSingleton建立bean的例項
4.標記這個bean已經被建立了(允許迴圈依賴則Spring通過三級快取解決,提前將bean曝光)
5.遞迴獲取依賴的bean並完成例項化
6.當前bean進行屬性注入

在非懶載入bean隨容器啟動時,載單例bean首次訪問時進行例項化,通過呼叫getBean訪問getSingleton

if (mbd.isSingleton()) {
    //入參ObjectFactory通過getObject獲取最終的例項
    sharedInstance = this.getSingleton(beanName, () -> {
        try {
            //實現ObjectFactory介面的getObject()方法
            return this.createBean(beanName, mbd, args);
        } catch (BeansException var5) {
            this.destroySingleton(beanName);
            throw var5;
        }
    });
    //判斷建立的bean是否為factoryBean,如果是則通過factoryBean去建立例項
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}


Spring三級快取解決迴圈依賴

只有單例bean且在earlySingletonExposure為true時(預設為true)才允許迴圈依賴的情況下才有二三級快取

Spring 能解決的迴圈依賴有:通過 setter 注入的迴圈依賴、通過屬性注入的迴圈依賴,當構造器出現迴圈依賴則無法解決,所以需要先用建構函式建立一個 “不完整” 的 bean 例項

//singletonObjects 一級快取:例項化儲存的單例 bean 物件
private final Map<String, Object> singletonObjects;
//earlySingletonObjects 二級快取:還未進行屬性填充 
private final Map<String, Object> earlySingletonObjects;
//singletonFactories 三級快取:存放BeanName與bean工廠
private final Map<String, ObjectFactory<?>> singletonFactories;
//在Bean開始例項化時將bean存放,建立完成時會將其移出
private final Set<String> singletonsCurrentlyInCreation;
//Bean被建立完成後新增
private final Set<String> alreadyCreated;
//已經註冊的單例bean,三級快取中任意添加了都會同步新增到這裡
private final Set<String> registeredSingletons

解決迴圈依賴的原理

1.滿足條件下,比如有兩個bean A和B迴圈依賴,在A例項化getBean時會暴露到三級快取中,進行屬性注入populate時發現依賴B,則先去例項化B;

2.B例項化過程中也會暴露到三級快取中,在注入屬性時又發現依賴於A;

3.此時再次訪問getBean(A),由於A已經存在三級快取,所以在獲取A快取時通過三級快取獲取A的原始bean新增到二級快取中,並返回快取的A例項,A注入到B;

4.B完成屬性注入之後放入一級快取中,然後A完成了屬性的注入並獲取了二級快取,清除二級快取放入一級快取

singleton例項由實現ObjectFactory介面getObject方法返回createBean()實現

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Map var3 = this.singletonObjects;
    synchronized(this.singletonObjects) {
        //還是先從快取中拿
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            //當前bean是正在destruction狀態,預設false
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException();
            }
            //建立例項前的驗證
            //先校驗beanName不是要在建立檢查排除掉的(inCreationCheckExclusions快取)
            //且新增到正在建立bean的快取singletonsCurrentlyInCreation中,新增失敗就表示已存在
            this.beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            try {
                //執行creatBean()方法,由入參singletonFactory中getObject方法返回
                //如果執行迴圈依賴則返回的是二級快取
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } finally {
                //從singletonsCurrentlyInCreation移除beanName
                this.afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                /**建立新的Bean成功新增到一級快取中,並移除二三級快取
                    this.singletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                    this.earlySingletonObjects.remove(beanName);
                    this.registeredSingletons.add(beanName); //已註冊的bean
                **/
                this.addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}


當earlySingletonExposure為true表示允許迴圈依賴從而新增一個三級快取ObjectFactory

protected Object createBean(String beanName, RootBeanDefinition mbd,  Object[] args)  {
    RootBeanDefinition mbdToUse = mbd;
    //...
    //當存在InstantiationAwareBeanPostProcessor時執行處理器的applyBeanPostProcessorsBeforeInstantiation和applyBeanPostProcessorsAfterInitialization
    Object beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
    if (beanInstance != null) {
        return beanInstance;
    }
    //返回完整的Bean例項
    beanInstance = this.doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    //bean包裝類
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        //如果是factoryBean則清除快取
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        //建立Bean例項,進行包裝,實現構造器依賴注入
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }
    //獲取原始物件和其型別
    Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    //MergedBeanDefinitionPostProcessor,處理RootBeanDefinition
    //@Autowired通過子類AutowiredAnnotationBeanPostProcessor實現將標有註解的欄位和方法放入快取
    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    //滿足單例,允許迴圈依賴,正在例項建立中三個條件
    boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
    if (earlySingletonExposure) {
        //解決迴圈依賴,新增三級快取singletonFactory,移出二級快取
        //this.singletonFactories.put(beanName, singletonFactory);
        //this.earlySingletonObjects.remove(beanName);
        //this.registeredSingletons.add(beanName);
        this.addSingletonFactory(beanName, () -> {
            //實現SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法
            //可以實現AOP的邏輯,如果沒有增強處理則三級快取就是原始的bean
            return this.getEarlyBeanReference(beanName, mbd, bean);
        });
    }
    Object exposedObject = bean;
    //完成屬性和方法的依賴注入
    this.populateBean(beanName, mbd, instanceWrapper);
    //bean增強,@PostConstruct>InitializingBean>init()
    //依次:處理aware介面,執行BeanPostProcessors中postProcessBeforeInitialization方法,呼叫初始化方法init-Methods,執行BeanPostProcessor的postProcessAfterInitialization方法
    exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    //解決迴圈依賴
    if (earlySingletonExposure) {
        //呼叫過載的方法,在獲取快取時也訪問的是這個方法,用於獲取二級快取
        Object earlySingletonReference = this.getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            //initializeBean沒有處理bean則將二級快取進行進行暴露
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
                //initializeBean處理之後會產生一個代理物件且有被依賴的bean
            } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                //將這些依賴exposedObject的bean陣列移除,因為Bean已經不是原來的bean了
                String[] dependentBeans = this.getDependentBeans(beanName);
                ...
            }
        }
    }
    //註冊用於銷燬的bean,執行銷燬操作的有三種:自定義destroy方法、DisposableBean介面、DestructionAwareBeanPostProcessor
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
    return exposedObject;
}


通過三級快取singletonObject獲取二級快取的過載的方法

---DefaultSingletonBeanRegistry
//allowEarlyReference表示是否允許從singletonFactories中通過getObject拿到物件,預設true
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//從一級快取中獲取
    Object singletonObject = this.singletonObjects.get(beanName);
    //isSingletonCurrentlyInCreation表示正在進行建立中,且從一級快取中未獲取到例項
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        Map var4 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            //二級快取也不存在且允許迴圈依賴
            if (singletonObject == null && allowEarlyReference) {
            	//獲取ObjectFactory,從例項工廠獲取例項
                ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                //允許迴圈依賴則會存在一個三級快取
                if (singletonFactory != null) {
                	//通過這個三級快取的getObject()方法實現,如果沒有增強處理則是原始bean
                    singletonObject = singletonFactory.getObject();
                    //獲取到了則新增到二級快取中,並移除三級快取的物件
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
	//這個getSingleton方法的過載就是從快取獲取bean例項,沒有則去建立新的例項
    return singletonObject;
}

prototypes例項的建立

多例的快取放在ThreadLocal快取中,每個執行緒獲取的都是通過getBean例項化的新物件,將 beanName 新增到 prototypesCurrentlyInCreation 快取

private final ThreadLocal<Object> prototypesCurrentlyInCreation;

try {
    //例項化之前先新增快取到當前執行緒中
    this.beforePrototypeCreation(beanName);
    prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
    //清除當前執行緒的快取
    this.afterPrototypeCreation(beanName);
}

protected void beforePrototypeCreation(String beanName) {
    //prototype的bean的beanName集合
    Object curVal = this.prototypesCurrentlyInCreation.get();
    // 將ThreadLocal設定成當前的beanName
    if (curVal == null) {
        this.prototypesCurrentlyInCreation.set(beanName);
    }
    // 如果快取不為空且為String型別,則表示只有一個beanName
    else if (curVal instanceof String) {
        Set<String> beanNameSet = new HashSet<String>(2);
        beanNameSet.add((String) curVal);
        beanNameSet.add(beanName);
        this.prototypesCurrentlyInCreation.set(beanNameSet);
    }
    // 如果存在多個beanName,將當前的beanName新增到Set
    else {
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.add(beanName);
    }
}

initializeBean的順序

完成屬性注入之後執行initializeBean,先說結論,先通過處理器執行@PostConstruct註解標註的方法,通過invokeInitMethods先執行InitializingBean介面的afterPropertiesSet()方法,最後才執行init-method方法

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    //如果bean是aware實現類,則將beanName,beanFactory分別新增到BeanNameAware和BeanFactoryAware
    this.invokeAwareMethods(beanName, bean);
    Object wrappedBean; 
    //執行BeanPostProcessor的applyBeanPostProcessorsBeforeInitialization方法
    //InitDestroyAnnotationBeanPostProcessor在這一步會執行@PostConstruct標註的方法
    wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
	// 處理InitializingBean和init-method
    this.invokeInitMethods(beanName, wrappedBean, mbd);
    wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    return wrappedBean;
}

執行InitDestroyAnnotationBeanPostProcessor處理器時找到並invoke被標註的方法

//在方法上通過註解@PostConstruct標註為初始化的方法
//標註為初始化的方法
@PostConstruct
public void init(){
    System.out.println("init");
}
//銷燬的方法
@PreDestroy
public void destroy(){
    System.out.println("destroy");
}

進入invokeInitMethods方法,首先會判斷bean是否實現了InitializingBean,如果是則執行afterPropertiesSet()方法.下一步從initMethods獲取init的方法,init-method是在xml解析時封裝在beanDefinition的initMethods

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    //InitializingBean實現類完成初始化方法
    boolean isInitializingBean = bean instanceof InitializingBean;
    ((InitializingBean)bean).afterPropertiesSet();
	//init-method指定的初始化方法
    String initMethodName = mbd.getInitMethodName();
    this.invokeCustomInitMethod(beanName, bean, mbd);
}

//實現InitializingBean介面的afterPropertiesSet方法
@Service
public class TxService implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean");
    }
}

也可以通過@Bean指定init-method方法:

@Bean(initMethod = "init")
public InitService getInit(){
    return new InitService();
}
public class InitService {
    public void init(){
        System.out.println("init");
    }
}

屬性注入

DI目的是在初始化物件時,根據物件中的屬性依賴, 動態將容器中bean按需注入進去,無需手動維護依賴關係,比如兩個交給spring管理的bean,其中A依賴B,這時就需要先例項化B並注入到A中,實現屬性填充;

構造器注入

首先要回到doCreateBean方法中有一個createBeanInstance就是用於構造器注入

//構造器例項化
Object instance = constructor.newInstance();


根據beanName、mbd建立Bean例項,args是bean的建構函式引數,根據args選擇不同的建構函式

//進入doCreateBean方法,通過createBeanInstance建立beanDefinition對應的包裝例項
instanceWrapper = this.createBeanInstance(beanName, mbd, args);

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    //ClassUtils.forName(className, dynamicLoader);
    Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
    //理解為提供一個靜態方法回撥建立例項,比如static MyBean createMyBean(){new MyBean();}
    //beanDefinition.setInstanceSupplier(SupplierBean::createUser);
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return this.obtainFromSupplier(instanceSupplier, beanName);
    } else if (mbd.getFactoryMethodName() != null) {
        //使用工廠方法去建立例項
        return this.instantiateUsingFactoryMethod(beanName, mbd, args);
    } else {
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            //不為null,則表示快取有被解析的構造器
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                //判斷是否需要自動注入,預設是false
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
        //args為null
        if (resolved) {
            //true建構函式自動注入,false選擇使用預設的建構函式
            return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
        } 
		//SmartInstantiationAwareBeanPostProcessor選擇候選的建構函式
        //@Autowired就是通過子類AutowiredAnnotationBeanPostProcessor實現注入
        Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        //ctors不為空 || mbd的注入方式為AUTOWIRE_CONSTRUCTOR || mdb定義了建構函式的引數值 || args不為空,執行建構函式自動注入
        if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
            //理解為public的構造器
            ctors = mbd.getPreferredConstructors();
            //autowireConstructor自動注入的選舉流程:優先public方法,根據入參的args引數個數(做解析返回最終的引數個數)找到符合引數大於或等於的候選構造器,instantiateBean沒有args引數當然預設使用無參構造器;和autowireConstructor一樣最後通過BeanUtils.instantiateClass(ctor, args)構建原始例項;
            return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
        } else {
            return this.autowireConstructor(beanName, mbd, ctors, args);
        }
    }
}

determineConstructorsFromBeanPostProcessors方法用於執行determineCandidateConstructors方法,主要的實現類有AutowiredAnnotationBeanPostProcessor,看處理器名字就知道是處理@Autowired,主要作用也是用於給定 bean 的候選建構函式,因為原始碼很長,包括處理器是如何載入到容器中,暫時留個坑,大致理解一下處理器determineCandidateConstructors方法的作用

1.處理@Lookup註解,如果一個單例BeanA依賴多例的BeanB,因為BeanA是單例,在初始化一次之後就放入快取,所以BeanB也是beanA首次初始化依賴的beanB時所建立的例項;使用@Lookup註解標註在構造器方法或者普通方法用於生成子類去重寫這個方法,每次呼叫時會去調子類則形成依賴的更新;將@Lookup方法新增到lookupMethodsChecked快取

2.從candidateConstructorsCache.get(beanClass)快取中獲取已存在解析的構造器,否則繼續通過放射方法getDeclaredConstructors獲取類的所有構造器放入rawCandidates快取

3.遍歷所有構造器並進行分類快取:
// 存放@Autowire註解的建構函式
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
// 存放@Autowire註解,並且require=true的建構函式
Constructor<?> requiredConstructor = null;
// 存放預設的建構函式
Constructor<?> defaultConstructor = null;

4.如果不存在required=true則將預設構造器放入candidates,然後將集合轉為Constructor<?>[]陣列,如果只有構造器且非預設則單獨放入候選構造器陣列,其他情況返回空new Constructor<?>[0]陣列,封裝到構造器快取


以一個簡單的例項來理解整個構造器注入依賴的流程:constructor-arg解析封裝在ConstructorArgumentValues中,所以ConstructorArgumentValues有值時通過autowireConstructor方法選擇構造器進行例項化,優先選擇public作為候選構造器,獲取到依賴的屬性通過resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues)去建立依賴的sub例項,@Autowired用在構造器上主要是獲取候選構造器

public class Super {
    private String name;
    private Sub sub;
    //構造器
    public Super(String name, Sub sub) {
        this.name = name;
        this.sub = sub;
    }
}

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//當獲取getBean時開始例項化
Object aSuper = context.getBean("super");

<!--構造器方式注入constructor-arg-->
<bean id="super" class="cn.mywork.spring.Super">
    <constructor-arg name="name" value="superName"/>
    <constructor-arg name="sub" ref="sub"/>
</bean>
<!--注入的物件-->
<bean id="sub" class="cn.mywork.spring.Sub">
    <property name="age" value="30"/>
</bean>


屬性自動裝配

如果是byName注入模式,則通過autowireByName方法呼叫getBean例項化依賴的Bean並注入到當前Bean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    //PropertyValues對bean的屬性值的封裝,比如依賴的bean資訊
    PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;
    /*AutowireMode自動裝配型別
        int AUTOWIRE_NO = 0;  預設裝配模式,註解注入的方式
        int AUTOWIRE_BY_NAME = 1;  通過beanName注入依賴
        int AUTOWIRE_BY_TYPE = 2;  根據bean型別注入
        int AUTOWIRE_CONSTRUCTOR = 3; 構造器注入
    */
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {
        MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
        if (resolvedAutowireMode == 1) {
            /* 自動裝配byName,將sub注入到Super中,只需要保證sub的beanName和屬性名一致即可
            	public class Super{
            		private Sub sub1;
            	}
            	<bean id="super" class="com.xxx.Super" autowire="byName">
            	<bean id="sub1" class="com.xxx.Sub">
            */
            //獲取依賴的屬性名稱作為beanName去getBean,再將依賴關係註冊到bean的dependy-on的快取中
            this.autowireByName(beanName, mbd, bw, newPvs);
        }
        /* 自動裝配byType,通過sub屬性型別Sub.class去匹配sub的bean並進行註冊
        	通過doResolveDependency方法就是@Autowired查詢bean的第一個方式,找到class型別對應
        	的所有bean,再根據條件進行篩選的依賴的bean注入,並將依賴關係註冊到快取中
         */
        if (resolvedAutowireMode == 2) {
            this.autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
    //執行存在InstantiationAwareBeanPostProcessor的postProcessProperties方法
    //處理@Autowire標註的屬性注入
    while(...) {
        pvs = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    }
    //property屬性注入
    this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}


註解@Autowired注入原理

回到doCreateBean,當構造器注入完成後繼續往下執行applyMergedBeanDefinitionPostProcessors(),這個方法用於處理MergedBeanDefinitionPostProcessor處理器的postProcessMergedBeanDefinition,實現該處理器會將合併的BeanDefinition作為方法的引數進行增強

這一步的主要作用就是將被@Autowired標註的set方法和欄位資訊封裝到metadata

this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
//子類AutowiredAnnotationBeanPostProcessor的實現,處理@Autowired
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    //在指定Bean中查詢使用@Autowire註解的元資料
    //獲取欄位和set方法上的@Autowired註解資訊(不支援static修飾的欄位和方法)
    //方法獲取descriptor.getWriteMethod()判斷是否為set方法
    //method、required、pd封裝成AutowiredMethodElement新增到InjectionMetadata快取
    InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);
    metadata.checkConfigMembers(beanDefinition);
}

回到populateBean方法,完成byName自動裝配後往下執行,通過postProcessProperties方法用於完成被@Autowired標註的屬性注入/方法注入,實現注入的方法inject()有兩個實現類,分別用於set方法和欄位屬性注入

protected void inject(Object target, String beanName,  PropertyValues pvs)  {}

欄位屬性注入優先通過屬性的name作為BeanName去找bean快取,如果沒有快取則根據classType去獲取bean,在doResolveDependency方法中會進行詳細查詢依賴bean的過程:根據名稱快速查詢快取,沒有快取則通過findAutowireCandidates根據型別 type 查詢名稱 beanNames作為候選,通過@Qualifier值進行篩選,和選擇候選構造器一樣;如果候選者個數大於1則繼續判斷@Primary(表示優先)和@Priority(數字越小優先順序越高),從而選出最終注入的bean

// 設定欄位訪問性
ReflectionUtils.makeAccessible(field);
// 通過反射為屬性賦值,將解析出來的bean例項賦值給field
field.set(bean, value);


@Resource先找預設的bean id(bean註冊的時候不指定beanId則預設為類的簡單名),如果介面有多個實現,則使用@Resource(name = “”)去指定,當注入的例項有多個實現類時,使用Resource

方法的注入:必須是set方法,在封裝metadata時就通過內省的方式判斷註解標註的方法是否為writeMethod(也就是set方法)

//內省機制
BeanInfo beanInfo = Introspector.getBeanInfo(superClass);
PropertyDescriptor[] ps = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : ps){
    if (pd.getName().equals("name")){
        //set方法
        pd.getWriteMethod();
    }
}
//設定set方法的訪問性
ReflectionUtils.makeAccessible(method);
//通過反射執行方法
method.invoke(bean, value);

PropertyValues屬性注入

populateBean方法最後一步applyPropertyValues將所有PropertyValues中的屬性填充到bean中,比如通過xml配置屬性依賴注入,在loadBeanDefinitions解析配置項時便將屬性值封裝在PropertyValues中

<!-- 配置setter屬性注入的標籤為property->
<bean id="student" class="cn.mywork.spring.Student">
    <!--直接將值用value屬性填入-->
    <property name="name" value="studentName"/>
    <!--物件引入,需要ref去引入bean的id-->
    <property name="sub" ref="sub"/>
    <!--基本型別的陣列注入 array標籤-->
    <property name="nums">
        <array>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </array>
    </property>
    <!--物件集合的注入list標籤-->
    <property name="subList">
        <list>
            <ref bean="sub"/>
            <ref bean="sub"/>
        </list>
    </property>
    <!--map集合的注入 map標籤-->
    <property name="superMap">
        <map>
            <entry key="key1" value-ref="super"/>
            <entry key="key2" value-ref="super"/>
        </map>
    </property>
</bean>

<!--注入的屬性-->
<bean id="sub" class="cn.mywork.spring.Sub">
    <property name="age" value="20"/>
</bean>
<bean id="super" class="cn.mywork.spring.Super">
    <property name="name" value="superName"/>
</bean>

解析配置項的property屬性型別,返回對應型別的值,核心方法就是setPropertyValues在很深入的內部進行實現,有BeanPropertyHandler方法注入和FieldPropertyHandler欄位注入兩種實現

//set方法進行屬性注入
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(BeanWrapperImpl.this.getWrappedInstance(), new Object[]{value});
//欄位屬性注入
ReflectionUtils.makeAccessible(this.field);
this.field.set(DirectFieldAccessor.this.getWrappedInstance(), value);