如何使用Spring的FactoryBean介面

不學無數的程式設計師發表於2019-01-10

如何使用Spring的FactoryBean介面

在Spring容器中有兩類的Bean,一類是普通的Bean,一類是工廠Bean。這兩種Bean都是被Spring的容器進行管理的。而Spring也提供了一個介面用於擴充套件工廠Bean,我們只要實現org.springframework.beans.factory.FactoryBean即可。

如何使用

首先我們看一下FactoryBean介面

public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class<?> getObjectType();

	boolean isSingleton();

}

複製程式碼

這三個方法的作用分別是

  • getObject:返回本工廠建立的物件例項。此例項也許是共享的,依賴於該工廠返回的是單例或者是原型。
  • getObjectType:返回物件型別
  • isSingleton:表示被工廠建立的例項是否是單例

現在讓我們開始使用,建立一個UserFactory用來建立例項User


public class User {

    private String name;
    private Integer age;
-----get set 方法
}

複製程式碼

UserFactory工廠類

public class UserFactory implements FactoryBean<User> {
    private String name;
    private Integer age;
    
    @Override
    public User getObject() throws Exception {
        return new User(name,age);
    }

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

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

複製程式碼

新增配置類將UserFactory加入到容器中

@Configuration
public class FactoryBeanAppConfig {

    @Bean
    public UserFactory userFactory(){
        UserFactory userFactory = new UserFactory();
        userFactory.setAge(10);
        userFactory.setName("Grace");
        return userFactory;
    }

}

複製程式碼

接下來我們就能通過UserFactory工廠類進行建立User

public class BeanFactoryTest extends BaseTest{

    @Autowired
    private User user;

    @Test
    public void testBeanFactory(){
        assertEquals(new Integer(10),user.getAge());
        assertEquals("Grace",user.getName());
    }
}

複製程式碼

此時我們Debug也能看到其我們自動注入的User類就是通過UserFactory建立的例項

如何使用Spring的FactoryBean介面

載入順序

有時候我們需要在工廠Bean建立之後,但是getObject方法執行之前執行一些動作,例如資源配置檢查之類的動作的話,我們可以使用@PostConstruct註解在方法上,那麼此方法就會在執行getObject()方法執行之前先執行。

此時我們在UserFactory工廠類中修改如下,增加@PostConstruct註解的方法,並且增加列印日誌。

public class UserFactory implements FactoryBean<User> {
    private String name;
    private Integer age;

    @Override
    public User getObject() throws Exception {
        System.out.println("getObject Begin");
        return new User(name,age);
    }

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

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

    @PostConstruct
    public void Initialize(){
        System.out.println("Initialize Begin");
    }
}

複製程式碼

此時我們執行就會發現執行順序

如何使用Spring的FactoryBean介面

AbstractFactoryBean

Spring為我們提供了一個關於FactoryBean的抽象類AbstractFactoryBean為我們簡化了操作。我們直接繼承此類就能更加方便的建立單例或者非單例的實體類了。接下來我們就演示一下如何建立單例和非單例的類。首先先建立兩個工廠,一個工廠SingleUserFactory負責建立單例,一個工廠NonSingleUserFactory負責建立非單例

public class SingleUserFactory extends AbstractFactoryBean<User> {

    private String name;
    private Integer age;

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

    @Override
    protected User createInstance() throws Exception {
        return new User(name,age);
    }
--get set方法
}

複製程式碼

NonSingleUserFactory

public class NonSingleUserFactory extends AbstractFactoryBean<User> {

    private String name;
    private Integer age;
	//設定為非單例模式
    public NonSingleUserFactory(){
        setSingleton(false);
    }

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

    @Override
    protected User createInstance() throws Exception {
        return new User(name,age);
    }
    
---- get set方法
}

複製程式碼

並且在配置檔案中加入對這兩個工廠類的配置

    @Bean(name = "singleUser")
    public SingleUserFactory getSingle(){
        SingleUserFactory singleUserFactory = new SingleUserFactory();
        singleUserFactory.setAge(12);
        singleUserFactory.setName("Single");
        return singleUserFactory;
    }

    @Bean(name = "nonSingleUser")
    public NonSingleUserFactory getNonSingle(){
        NonSingleUserFactory nonSingleUserFactory = new NonSingleUserFactory();
        nonSingleUserFactory.setAge(12);
        nonSingleUserFactory.setName("NonSingle");
        return nonSingleUserFactory;
    }

複製程式碼

在測試類中測試如下

public class SingleBeanFactoryTest extends BaseTest{
    @Resource(name = "singleUser")
    private User user1;
    @Resource(name = "singleUser")
    private User user2;
    @Resource(name = "nonSingleUser")
    private User user3;
    @Resource(name = "nonSingleUser")
    private User user4;

    @Test
    public void testSingleBean(){
        assertTrue(user1 == user2);
        assertTrue(user3 != user4);
    }
}

複製程式碼

我們檢視類的路徑就可以知道哪些類是一樣的了

如何使用Spring的FactoryBean介面

從結果中我們可以看到SingleUserFactory工廠類建立的都是單例的物件,而NonSingleUserFactory建立的都是非單例的物件。如果是建立單例的那麼就無需設定singleton的值,因為他是預設為True的。

使用FactoryBean能夠在Spring中更好更便捷的建立管理一些有著複雜構造邏輯的實體類。

原始碼可在github中檢視

相關文章