寻找获取Bean 的入口
生活随笔
收集整理的這篇文章主要介紹了
寻找获取Bean 的入口
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
AbstractBeanFactory 的getBean()相關方法的源碼如下:
//獲取IOC容器中指定名稱的Bean @Override public Object getBean(String name) throws BeansException {//doGetBean才是真正向IoC容器獲取被管理Bean的過程return doGetBean(name, null, null, false); }//獲取IOC容器中指定名稱和類型的Bean @Override public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {//doGetBean才是真正向IoC容器獲取被管理Bean的過程return doGetBean(name, requiredType, null, false); }//獲取IOC容器中指定名稱和參數的Bean @Override public Object getBean(String name, Object... args) throws BeansException {//doGetBean才是真正向IoC容器獲取被管理Bean的過程return doGetBean(name, null, args, false); }//獲取IOC容器中指定名稱、類型和參數的Bean public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)throws BeansException {//doGetBean才是真正向IoC容器獲取被管理Bean的過程return doGetBean(name, requiredType, args, false); }@SuppressWarnings("unchecked") //真正實現向IOC容器獲取Bean的功能,也是觸發依賴注入功能的地方 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//根據指定的名稱獲取被管理Bean的名稱,剝離指定名稱中對容器的相關依賴//如果指定的是別名,將別名轉換為規范的Bean名稱final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.//先從緩存中取是否已經有被創建過的單態類型的Bean//對于單例模式的Bean整個IOC容器中只創建一次,不需要重復創建Object sharedInstance = getSingleton(beanName);//IOC容器創建單例模式Bean實例對象if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {//如果指定名稱的Bean在容器中已有單例模式的Bean被創建//直接返回已經創建的Beanif (isSingletonCurrentlyInCreation(beanName)) {logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}//獲取給定Bean的實例對象,主要是完成FactoryBean的相關處理//注意:BeanFactory是管理容器中Bean的工廠,而FactoryBean是//創建創建對象的工廠Bean,兩者之間有區別bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.//緩存沒有正在創建的單例模式Bean//緩存中已經有已經創建的原型模式Bean//但是由于循環引用的問題導致實例化對象失敗if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.//對IOC容器中是否存在指定名稱的BeanDefinition進行檢查,首先檢查是否//能在當前的BeanFactory中獲取的所需要的Bean,如果不能則委托當前容器//的父級容器去查找,如果還是找不到則沿著容器的繼承體系向父級容器查找BeanFactory parentBeanFactory = getParentBeanFactory();//當前容器的父級容器存在,且當前容器中不存在指定名稱的Beanif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.//解析指定Bean名稱的原始名稱String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {// Delegation to parent with explicit args.//委派父級容器根據指定名稱和顯式的參數查找return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.//委派父級容器根據指定名稱和類型查找return parentBeanFactory.getBean(nameToLookup, requiredType);}}//創建的Bean是否需要進行類型驗證,一般不需要if (!typeCheckOnly) {//向容器標記指定的Bean已經被創建markBeanAsCreated(beanName);}try {//根據指定Bean名稱獲取其父級的Bean定義//主要解決Bean繼承時子類合并父類公共屬性問題final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.//獲取當前Bean所有依賴Bean的名稱String[] dependsOn = mbd.getDependsOn();//如果當前Bean有依賴Beanif (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//遞歸調用getBean方法,獲取當前Bean的依賴BeanregisterDependentBean(dep, beanName);//把被依賴Bean注冊給當前依賴的BeangetBean(dep);}}// Create bean instance.//創建單例模式Bean的實例對象if (mbd.isSingleton()) {//這里使用了一個匿名內部類,創建Bean實例對象,并且注冊給所依賴的對象sharedInstance = getSingleton(beanName, () -> {try {//創建一個指定Bean實例對象,如果有父級繼承,則合并子類和父類的定義return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.//顯式地從容器單例模式Bean緩存中清除實例對象destroySingleton(beanName);throw ex;}});//獲取給定Bean的實例對象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}//IOC容器創建原型模式Bean實例對象else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.//原型模式(Prototype)是每次都會創建一個新的對象Object prototypeInstance = null;try {//回調beforePrototypeCreation方法,默認的功能是注冊當前創建的原型對象beforePrototypeCreation(beanName);//創建指定Bean對象實例prototypeInstance = createBean(beanName, mbd, args);}finally {//回調afterPrototypeCreation方法,默認的功能告訴IOC容器指定Bean的原型對象不再創建afterPrototypeCreation(beanName);}//獲取給定Bean的實例對象bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}//要創建的Bean既不是單例模式,也不是原型模式,則根據Bean定義資源中//配置的生命周期范圍,選擇實例化Bean的合適方法,這種在Web應用程序中//比較常用,如:request、session、application等生命周期else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);//Bean定義資源中沒有配置生命周期范圍,則Bean定義不合法if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {//這里又使用了一個匿名內部類,獲取一個指定生命周期范圍的實例Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});//獲取給定Bean的實例對象bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.//對創建的Bean實例對象進行類型檢查if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean; }通過上面對向IOC 容器獲取Bean 方法的分析,我們可以看到在Spring 中,如果Bean 定義的單例模式(Singleton),則容器在創建之前先從緩存中查找,以確保整個容器中只存在一個實例對象。如果Bean定義的是原型模式(Prototype),則容器每次都會創建一個新的實例對象。除此之外,Bean 定義還可以擴展為指定其生命周期范圍。
上面的源碼只是定義了根據Bean 定義的模式,采取的不同創建Bean 實例對象的策略,具體的Bean實例對象的創建過程由實現了ObjectFactory 接口的匿名內部類的createBean() 方法完成,ObjectFactory 使用委派模式, 具體的Bean 實例創建過程交由其實現類
AbstractAutowireCapableBeanFactory 完成,我們繼續分析AbstractAutowireCapableBeanFactory的createBean()方法的源碼,理解其創建Bean 實例的具體實現過程。
?
?
總結
以上是生活随笔為你收集整理的寻找获取Bean 的入口的全部內容,希望文章能夠幫你解決所遇到的問題。