javascript
Spring杂谈 | 什么是ObjectFactory?什么是ObjectProvider?
在Spring的學習過程中,總是學的越多,不懂的越多。本來只是想將ApplicationContext的相關內容全部梳理一遍,結果發現涉及的東西越來越多,比如上篇文章中的ResolvableType,到這篇文章介紹的ObjectFactory跟ObjectProvider。不過想想也沒辦法,一步一步往前走唄,在這個過程中也確實學到了很多東西。廢話不多說,直接進入正文。
”ObjectFactory
接口定義
//?一個對象工廠 public?interface?ObjectFactory<T>?{//?返回一個對象T?getObject()?throws?BeansException;}這個接口的定義非常簡單,就是一個對象工廠,定義了一個返回對象的工廠方法。回顧我們直接介紹過的一個內容FactroyBean,其接口定義如下:
public?interface?FactoryBean<T>?{@NullableT?getObject()?throws?Exception;@NullableClass<?>?getObjectType();default?boolean?isSingleton()?{return?true;}}可以看到兩者都有一個getObject方法,那么它們有什么區別或者聯系呢?
跟FactoryBean的區別及聯系
聯系
二者在功能設計上是沒有什么聯系的,他們最大的共同點就是都采用了工廠模式,通過工廠模式來返回一個對象
區別
FactoryBean在BeanFacotry的實現中有著特殊的處理,如果一個對象實現了FactoryBean?那么通過它get出來的對象實際是factoryBean.getObject()得到的對象,如果想得到FactoryBean必須通過在?'&' + beanName的方式獲取
FactoryBean的設計主要是為了進行擴展容器中Bean的創建方式,所以FactoryBean著重于自定義創建對象過程,同時FactoryBean都會放到容器中,FactoryBean所創建的Bean也會放入容器中
ObjectFactory則只是一個普通的對象工廠接口。在Spring中主要兩處用了它
Object?get(String?name,?ObjectFactory<?>?objectFactory);這個方法的目的就是從對于的域中獲取到指定名稱的對象。為什么要傳入一個objectFactory呢?主要是為了方便我們擴展自定義的域,而不是僅僅使用request,session等域。
void?registerResolvableDependency(Class<?>?dependencyType,?@Nullable?Object?autowiredValue);粗看起來,好像這個方法跟ObjectFactory沒有什么關聯,但是我們留意這個方法上面的JavaDoc,其中有一段關于參數autowiredValue的介紹,如下
@param?autowiredValue?the?corresponding?autowired?value.?This?may?also?be?an *?implementation?of?the?{@link?org.springframework.beans.factory.ObjectFactory} *?interface,?which?allows?for?lazy?resolution?of?the?actual?target?value.從這段內容中我們能知道,autowiredValue這個參數可能就是一個ObjectFactory,主要是為了讓注入點能夠被延遲注入。Spring通過這種方式注入了request,response等對象
beanFactory.registerResolvableDependency(ServletRequest.class,?new?RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse.class,?new?ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession.class,?new?SessionObjectFactory()); beanFactory.registerResolvableDependency(WebRequest.class,?new?WebRequestObjectFactory());我們看看RequestObjectFactory的定義:
private?static?class?RequestObjectFactory?implements?ObjectFactory<ServletRequest>,?Serializable?{@Override//?是從當前線程中獲取的public?ServletRequest?getObject()?{return?currentRequestAttributes().getRequest();}@Overridepublic?String?toString()?{return?"Current?HttpServletRequest";} }當我們在某一個類中如果注入了ServletRequest對象,并不會直接創建一個ServletRequest然后注入進去,而是注入一個代理類,代理類中的方法是通過ObjectFactoryDelegatingInvocationHandler實現的,而這個對象中會持有一個RequestObjectFactory對象。基于此,我們可以通過下面這種方式直接注入request對象,并且保證線程安全
@RestController public?class?AutowiredRequestController?{@Autowiredprivate?HttpServletRequest?request; }-
ConfigurableListableBeanFactory類中的registerResolvableDependency方法,其定義如下,
-
Scope接口中的get方法,需要傳入一個ObjectFactory,如下:
ObjectProvider
接口定義
//?1.可以看到ObjectProvider本身繼承了ObjectFactory接口,所以它本身就是一個ObjectFactory //?2.從5.1之后,這個接口還多繼承了一個Iterable接口,意味著能對它進行迭代以及流式操作 public?interface?ObjectProvider<T>?extends?ObjectFactory<T>,?Iterable<T>?{//?返回用指定參數創建的bean,?如果容器中不存在,?拋出異常T?getObject(Object...?args)?throws?BeansException;//?如果指定類型的bean注冊到容器中,?返回?bean?實例,?否則返回?null@NullableT?getIfAvailable()?throws?BeansException;//?如果返回對象不存在,則用傳入的Supplier獲取一個Bean并返回,否則直接返回存在的對象default?T?getIfAvailable(Supplier<T>?defaultSupplier)?throws?BeansException?{T?dependency?=?getIfAvailable();return?(dependency?!=?null???dependency?:?defaultSupplier.get());}//?消費對象的一個實例(可能是共享的或獨立的),如果存在通過Consumer回調消耗目標對象。//?如果不存在則直接返回default?void?ifAvailable(Consumer<T>?dependencyConsumer)?throws?BeansException?{T?dependency?=?getIfAvailable();if?(dependency?!=?null)?{dependencyConsumer.accept(dependency);}}//?如果不可用或不唯一(沒有指定primary)則返回null。否則,返回對象。@NullableT?getIfUnique()?throws?BeansException;//?如果不存在唯一對象,則調用Supplier的回調函數default?T?getIfUnique(Supplier<T>?defaultSupplier)?throws?BeansException?{T?dependency?=?getIfUnique();return?(dependency?!=?null???dependency?:?defaultSupplier.get());}//?如果存在唯一對象,則消耗掉該對象default?void?ifUnique(Consumer<T>?dependencyConsumer)?throws?BeansException?{T?dependency?=?getIfUnique();if?(dependency?!=?null)?{dependencyConsumer.accept(dependency);}}//?返回符合條件的對象的Iterator,沒有特殊順序保證(一般為注冊順序)@Overridedefault?Iterator<T>?iterator()?{return?stream().iterator();}//?返回符合條件對象的連續的Stream,沒有特殊順序保證(一般為注冊順序)default?Stream<T>?stream()?{throw?new?UnsupportedOperationException("Multi?element?access?not?supported");}//?返回符合條件對象的連續的Stream。在標注Spring應用上下文中采用@Order注解或實現Order接口的順序default?Stream<T>?orderedStream()?{throw?new?UnsupportedOperationException("Ordered?element?access?not?supported");} }接口分析
在Spring4.3之前,如果你構造函數中要依賴另外一個bean,你必須顯示依賴@Autowired(這里不考慮使用了自動注入的方式,關于自動注入跟精確注入請參我之前的文章,《Spring官網閱讀》系列第二,三篇) ,像這樣子
@Service public?class?FooService?{private?final?FooRepository?repository;@Autowiredpublic?FooService(FooRepository?repository)?{this.repository?=?repository} }而在4.3版本之后,已經不需要這么做了,只要我們只提供了一個構造函數,并且構造函數所需要的參數都在Spring容器中(實際上官網中也指出,如果依賴關系是強制的,那么最好使用構造函數進行注入),那么不需要進行精確的指定使用@Autowired。相比于4.3版本這無疑簡化了我們的開發,但是這種隱式的注入仍然存在一些不足。例如,就上面的例子而言,如果容器中存在了一個以上的FooRepository甚至一個都沒有的情況下,拋出異常
?Parameter 0 of constructor in com.example.demo.FooServicerequired a bean of type 'com.example.demo.FooRepository' that could not be found.
或者是
No qualifying bean of type 'com.example.demo.FooRepository'' available: expected single matching bean but found 2:
”那么我們有什么辦法解決它呢?基于這個原因,ObjectProvider就出場了。如果注入實例為空時,使用ObjectProvider則避免了強依賴導致的依賴對象不存在異常;如果有多個實例,ObjectProvider的方法可以根據Bean實現的Ordered接口或@Order注解指定的先后順序獲取一個Bean。從而了提供了一個更加寬松的依賴注入方式。Spring主要在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency方法中使用了它,具體代碼如下:
@Override public?Object?resolveDependency(DependencyDescriptor?descriptor,?String?requestingBeanName,?Set<String>?autowiredBeanNames,?@Nullable?TypeConverter?typeConverter)?throws?BeansException?{//?descriptor代表當前需要注入的那個字段,或者方法的參數,也就是注入點//?ParameterNameDiscovery用于解析方法參數名稱descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());//?1.?Optional<T>if?(Optional.class?==?descriptor.getDependencyType())?{return?createOptionalDependency(descriptor,?requestingBeanName);//?2.?ObjectFactory<T>、ObjectProvider<T>}?else?if?(ObjectFactory.class?==?descriptor.getDependencyType()?||ObjectProvider.class?==?descriptor.getDependencyType())?{return?new?DependencyObjectProvider(descriptor,?requestingBeanName);//?3.?javax.inject.Provider<T>}?else?if?(javaxInjectProviderClass?==?descriptor.getDependencyType())?{return?new?Jsr330Factory().createDependencyProvider(descriptor,?requestingBeanName);}?else?{//?4.?@LazyObject?result?=?getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor,?requestingBeanName);//?5.?正常情況if?(result?==?null)?{result?=?doResolveDependency(descriptor,?requestingBeanName,?autowiredBeanNames,?typeConverter);}return?result;} }其實不管是上面的哪個情況,最終都會調用到正常情況下的doResolveDependency方法中。我們著重關注上面的第二種情況,可以看到當注入點為ObjectFactory或者ObjectProvider時,會new一個DependencyObjectProvider返回出去,那么返回的這個DependencyObjectProvider是什么呢?
其繼承關系如下:
這個DependencyObjectProvider對象,其實就是一個ObjectProvider,我們看看它是如何實現ObjectProvider中的方法的(方法的實現邏輯都差不多,這里就看一個方法):
public?Object?getIfAvailable()?throws?BeansException?{//?用于解決嵌套的情況,像這種:ObjectProvider<Optional<T>>if?(this.optional)?{return?createOptionalDependency(this.descriptor,?this.beanName);}else?{DependencyDescriptor?descriptorToUse?=?new?DependencyDescriptor(this.descriptor)?{@Overridepublic?boolean?isRequired()?{return?false;}};//?最終還是會調用這個方法解決依賴return?doResolveDependency(descriptorToUse,?this.beanName,?null,?null);} }從上面的過程中我們可以看出,但Spring中某個Bean的依賴類型為ObjectProvider時,我們不需要提供一個ObjectProvider類型的Bean到容器中,只需要提供一個T類型的Bean到容器中,容器會自動將其包裝成一個ObjectProvider,然后注入到依賴中。
而基于ObjectProvider的一系列方法,我們就能解決之前提到的問題。
ObjectProvider解決的問題
問題一
容器中沒有Bean時,拋出Parameter 0 of constructor in com.example.demo.FooServicerequired a bean of type 'com.example.demo.FooRepository' that could not be found.。
解決方式:
@Component public?class?IndexService?{B?b;public?IndexService(ObjectProvider<B>?b)?{this.b?=?b.getIfAvailable();} }但是上面這種解決方式的弊病也很明顯,就是b可能為空,則可能將異常從啟動階段轉移到業務運行階段。
問題二
容器中存在多個Bean時,拋出No qualifying bean of type 'com.example.demo.FooRepository'' available: expected single matching bean but found 2
@Component public?class?IndexService?{B?b;public?IndexService(ObjectProvider<B>?b)?{this.b?=?b.orderedStream().findFirst().orElse(null);} }當容器存在多個Bean,我們可以調用它的流式方法獲取一個自己想要的依賴。
總結
本文介紹了ObjectFactory跟ObjectProvider,對于ObjectFactory主要介紹了它的應用并且將其與我們之前學習過的FactoryBean做了比較。關于ObjectProvider也對其中定義的方法,以及它解決的問題做了分析。可能有些讀者覺得這些東西也不是很重要,并不影響核心代碼的閱讀。不過筆者在閱讀源碼過程中,看到了不去弄明白實在是難受,本人也是秉著愚公移山的精神慢慢啃,一個知識點一個知識點慢慢摸索,雖然這樣慢了點,但是能學到東西也是有很大滿足感的。不管怎么樣,我還是寫了這篇筆記,也會繼續寫下去。加油,為自己!
總結
以上是生活随笔為你收集整理的Spring杂谈 | 什么是ObjectFactory?什么是ObjectProvider?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring @Async注解
- 下一篇: 为什么只需要一个eden而需要两个sur