FactoryBean使用及真實(shí)應(yīng)用場景分享
一、FactoryBean是什么?
FactoryBean是spring提供的一個(gè)接口,可以通過它創(chuàng)建自定義對象工廠,將其注入spring容器后,會將其本身和其所要?jiǎng)?chuàng)建的bean一同注入容器。他和工廠模式中的工廠本質(zhì)上來沒有太大的區(qū)別,只不過一個(gè)是由spring 容器管理,一個(gè)是使用者自己管理。
FactoryBean中有三個(gè)方法如下:
public interface FactoryBean<T> {
/**
* The name of an attribute that can be
* {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
* {@link org.springframework.beans.factory.config.BeanDefinition} so that
* factory beans can signal their object type when it can't be deduced from
* the factory bean class.
* @since 5.2
*/
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
/**
返回我們所要?jiǎng)?chuàng)建的bean
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* <p>As with a {@link BeanFactory}, this allows support for both the
* Singleton and Prototype design pattern.
* <p>If this FactoryBean is not fully initialized yet at the time of
* the call (for example because it is involved in a circular reference),
* throw a corresponding {@link FactoryBeanNotInitializedException}.
* <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
* objects. The factory will consider this as normal value to be used; it
* will not throw a FactoryBeanNotInitializedException in this case anymore.
* FactoryBean implementations are encouraged to throw
* FactoryBeanNotInitializedException themselves now, as appropriate.
* @return an instance of the bean (can be {@code null})
* @throws Exception in case of creation errors
* @see FactoryBeanNotInitializedException
*/
@Nullable
T getObject() throws Exception;
/**
返回我們要?jiǎng)?chuàng)建bean的class類型
* Return the type of object that this FactoryBean creates,
* or {@code null} if not known in advance.
* <p>This allows one to check for specific types of beans without
* instantiating objects, for example on autowiring.
* <p>In the case of implementations that are creating a singleton object,
* this method should try to avoid singleton creation as far as possible;
* it should rather estimate the type in advance.
* For prototypes, returning a meaningful type here is advisable too.
* <p>This method can be called <i>before</i> this FactoryBean has
* been fully initialized. It must not rely on state created during
* initialization; of course, it can still use such state if available.
* <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
* {@code null} here. Therefore, it is highly recommended to implement
* this method properly, using the current state of the FactoryBean.
* @return the type of object that this FactoryBean creates,
* or {@code null} if not known at the time of the call
* @see ListableBeanFactory#getBeansOfType
*/
@Nullable
Class<?> getObjectType();
/**
是否為單例
* Is the object managed by this factory a singleton? That is,
* will {@link #getObject()} always return the same object
* (a reference that can be cached)?
* <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
* the object returned from {@code getObject()} might get cached
* by the owning BeanFactory. Hence, do not return {@code true}
* unless the FactoryBean always exposes the same reference.
* <p>The singleton status of the FactoryBean itself will generally
* be provided by the owning BeanFactory; usually, it has to be
* defined as singleton there.
* <p><b>NOTE:</b> This method returning {@code false} does not
* necessarily indicate that returned objects are independent instances.
* An implementation of the extended {@link SmartFactoryBean} interface
* may explicitly indicate independent instances through its
* {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
* implementations which do not implement this extended interface are
* simply assumed to always return independent instances if the
* {@code isSingleton()} implementation returns {@code false}.
* <p>The default implementation returns {@code true}, since a
* {@code FactoryBean} typically manages a singleton instance.
* @return whether the exposed object is a singleton
* @see #getObject()
* @see SmartFactoryBean#isPrototype()
*/
default boolean isSingleton() {
return true;
}
}
二、使用
在使用FactoryBean的時(shí)候,大多數(shù)是于spring提供的其他接口一起使用
1.創(chuàng)建我們需要的bean及其builder
代碼如下(示例):
@Data
public class Customize {
private String id;
private String name;
private int age;
private String address;
private String phone;
}
public class CustomizeBuilder {
private Customize customize;
public CustomizeBuilder builder() {
customize = new Customize();
return this;
}
public CustomizeBuilder id(String id) {
customize.setId(id);
return this;
}
public CustomizeBuilder name(String name) {
customize.setName(name);
return this;
}
public CustomizeBuilder age(int age) {
customize.setAge(age);
return this;
}
public CustomizeBuilder address(String address) {
customize.setAddress(address);
return this;
}
public CustomizeBuilder phone(String phone) {
customize.setPhone(phone);
return this;
}
public Customize build() {
return customize;
}
}
2.創(chuàng)建FactoryBean的實(shí)例
實(shí)現(xiàn)了InitializingBean 的 afterPropertiesSet()方法,該方法將在實(shí)現(xiàn)類的屬性加載完畢后調(diào)用。
代碼如下(示例):
@Component
public class CustomizeFactoryBean implements FactoryBean<Customize> , InitializingBean {
private Customize customize;
@Override
public Customize getObject() throws Exception {
return customize;
}
@Override
public Class<?> getObjectType() {
return Customize.class;
}
@Override
public void afterPropertiesSet() throws Exception {
if (customize == null){
customize= new CustomizeBuilder().builder()
.id("1")
.name("sun")
.age(18)
.address("beijing")
.phone("123456789")
.build();
}
}
}
之后我們在測試類中進(jìn)行測試
@SpringBootTest
class SpringBeanApplicationTests {
@Autowired
private Customize customize;
@Autowired
private CustomizeFactoryBean customizeFactoryBean;
@Test
public void contextLoads() throws Exception {
System.out.println(customizeFactoryBean);
System.out.println(customizeFactoryBean.getObject());
System.out.println(customize);
}
}
輸出:
com.agp.springbean.factorybean.CustomizeFactoryBean@5a592c70
Customize(id=1, name=sun, age=18, address=beijing, phone=123456789)
Customize(id=1, name=sun, age=18, address=beijing, phone=123456789)
對springboot進(jìn)行調(diào)試得到注入FactoryBean工廠得到的默認(rèn)對象就是其要?jiǎng)?chuàng)建的對象,可以通過&+factoryBeanName得到真實(shí)的bean工廠


整合mybatis
上述我們雖然通過@Component 將工廠注入到spring容器中,但是他真正的用法卻不是這樣。因?yàn)橄胍砸粋€(gè)bean我們可以通過很多種方式去完成。這種方法明顯是比較麻煩的,官方也不推薦使用spring相關(guān)注解注入。
下面來看看mybatis-spring是如何將spring整合mybatis的。
mybatis是如何運(yùn)行的?
mybatis的核心組件是 SqlSession,我們所有的sql操作都要使用這個(gè)接口完成。sqlSession又是由SqlSessionFactory構(gòu)建的。通過build方法創(chuàng)建出了SqlSessionFactory,即得到SqlSession。
具體解析過程這里不做介紹
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// 傳入配置文件,創(chuàng)建一個(gè)XMLConfigBuilder類
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 分兩步:
// 1、解析配置文件,得到配置文件對應(yīng)的Configuration對象
// 2、根據(jù)Configuration對象,獲得一個(gè)DefaultSqlSessionFactory
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
}
}
}
由上述代碼可知,只要我們擁有了SqlSessionFactory就擁有了mybatis的所有能力,剩下的就是怎么把SqlSessionFactory集成到spring中
在mybatis-spring中有這樣的一個(gè)Factorybean
public class SqlSessionFactoryBean
implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ContextRefreshedEvent>{
private SqlSessionFactory sqlSessionFactory;
....
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
/**
* {@inheritDoc}
*/
@Override
public Class<? extends SqlSessionFactory> getObjectType() {
return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSingleton() {
return true;
}
}
通過了buildSqlSessionFactory()來創(chuàng)建了SqlSessionFactory(),具體細(xì)節(jié)不做介紹。相信到了這里在結(jié)合我們在使用spring結(jié)合mybatis時(shí)的配置,大家都應(yīng)該能了解如何使用了,通過xml或者javaConfig的方式就SqlSessionFactoryBean加入到spring容器中將第三方的mybatis 集成到容器中,然后使用mybatis了
總結(jié)
FactoryBean主要是用來在spring初始化的過程中創(chuàng)建bean的工廠,個(gè)人理解它更像一個(gè)插件的接口??梢詫⒌谌降念悆?yōu)雅的加載到spring容器中??赡苓€有其他功能有待開發(fā)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot應(yīng)用中出現(xiàn)的Full GC問題的場景與解決
這篇文章主要為大家詳細(xì)介紹了SpringBoot應(yīng)用中出現(xiàn)的Full GC問題的場景與解決方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04
Spring Cloud Zuul自定義過濾器的實(shí)現(xiàn)
這篇文章主要介紹了自定義Spring Cloud Zuul過濾器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Idea+maven搭建SSH(struts2+hibernate5+spring5)環(huán)境的方法步驟
這篇文章主要介紹了Idea+maven搭建SSH(struts2+hibernate5+spring5)環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
spring中的特殊注解@RequiredArgsConstructor詳解
這篇文章主要介紹了spring中的特殊注解@RequiredArgsConstructor,包括注解注入,構(gòu)造器注入及setter注入,結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
詳解Spring Data JPA動態(tài)條件查詢的寫法
本篇文章主要介紹了Spring Data JPA動態(tài)條件查詢的寫法 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
Java利用文件輸入輸出流實(shí)現(xiàn)文件夾內(nèi)所有文件拷貝到另一個(gè)文件夾
這篇文章主要介紹了Java實(shí)現(xiàn)文件夾內(nèi)所有文件拷貝到另一個(gè)文件夾,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03

