前言
在spring中FactoryBean絕對是一種神奇的存在,和BeanFactory經常混淆,而且成為面試過程中經常被問到的問題,其實FactoryBean和BeanFactory很好理解,掌握一定的技巧即可。
初識
FactoryBean翻譯過來是工廠Bean,BeanFactory翻譯過來是Bean工廠,前者是bean工廠beanFactory中的一個bean,只不過這個bean和一般的bean不一樣,它有著自己的特殊之處,特殊在什麼地方那,在spring中提供了FactoryBean的介面,
package org.springframework.beans.factory; import org.springframework.lang.Nullable; public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
FactoryBean介面很簡單,就提供了三個方法getObject、getObjectType、isSingleton。就是這三個方法卻成為了spring中很多功能的基礎,搜尋整個spring的原始碼可以找到很多FactoryBean,除了spring自身提供的以外,在和一些框架進行整合的時候,同樣有FactoryBean的影子,比如和mybatis整合的時候的SqlSessionFactoryBean,
用法
這裡以springboot的環境為例演示下FactoryBean的用法,有需要原始碼的可關注公眾號【北漂程式設計師】私聊我。
自定義FactoryBean,僅在getObject方法內自己new了一個Student物件,且返回該物件;重寫了toString方法,為了測試用。
package com.example.myDemo.component; import com.example.myDemo.po.Student; import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component; @Component public class MyFactoryBean implements FactoryBean<Student> { @Override public Student getObject() throws Exception { Student student=new Student(); return student; } @Override public Class<?> getObjectType() { return null; } @Override public String toString() { return "MyFactoryBean{}"; } }
下面是Student類,很簡單就兩個屬性且重寫了toString方法,
package com.example.myDemo.po; public class Student { private String name; private String code; public Student(String name, String code) { this.name = name; this.code = code; } public Student() { } @Override public String toString() { return "Student{}"; } }
下面就是測試的方法了,
package com.example.myDemo; import com.example.myDemo.component.MyFactoryBean; import com.example.myDemo.po.Student; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.ApplicationContext; @SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) public class MyDemoApplication { public static void main(String[] args) { ApplicationContext ac=SpringApplication.run(MyDemoApplication.class, args); //獲得Student物件 Student stu=(Student) ac.getBean("myFactoryBean"); //獲得MyFactoryBean物件 MyFactoryBean myFactoryBean=(MyFactoryBean) ac.getBean("&myFactoryBean"); System.out.println("stu:"+stu); System.out.println("myFactoryBean:"+myFactoryBean); } }
先看下列印結果,
列印結果很奇怪通過“myFactoryBean”獲得了Student物件,通過“&myFactoryBean”獲得了MyFactoryBean物件。為什麼會這樣
功能解釋
看了上面的輸出結果很多小夥伴都很詫異,沒錯這就是FactoryBean的神奇,通俗點講FactoryBean是一個工廠bean,它是一種可以生產bean的bean,通過其getObejct方法生產bean。當然不論是FactoryBean還是FactoryBean生產的bean都是受spring管理的這點是沒有問題的,不然通過getBean方法是拿不到的。
上面講了那麼多到底FactoryBean的用處是什麼,前面講到FactroyBean的作用是生產一個Bean,這裡有一個疑問spring就是用來生產bean和管理bean的,為什麼還要有FactoryBean,FactoryBean的真正目的是讓開發者自己去定義那些複雜的bean並交給spring管理,如果bean中要初始化很多變數,而且要進行許多操作,那麼使用spring的自動裝配是很難完成的,所以spring的開發者把這些工作交給了我們。一個比較常見的例子是,在mybatis和spring整合的時候便有這樣一個FactoryBean,名字叫SqlSessionFactoryBean,這個FactoryBean的目的就是返回一個spring管理的SqlSessionFactory,使用過mybatis的都知道要建立一個sqlSessionFactory需要配置很多屬性,所以便有了SqlSessionFactoryBean,下面看下SqlSessionFactoryBean,
看下sqlSessionFactoryBean的getObejct方法
public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { this.afterPropertiesSet(); } return this.sqlSessionFactory; }
getObejctType方法
public Class<? extends SqlSessionFactory> getObjectType() { return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass(); }
isSingleton方法
public boolean isSingleton() { return true; }
總結
本篇文章主要帶小夥伴瞭解了FactoryBean這種特殊的Bean,它的作用就是生產Bean。這裡有個疑問在使用getBean方法的時候,為什麼傳入“myFactoryBean”和“&MyFactoryBean”兩個值返回值一個是FactoryBean生產的bean,一個是FactorBean那,下篇通過原始碼來揭祕,揭祕getObjectForBeanInstance方法的那些事,歡迎關注。