Spring組件註冊-BeanFactory使用

一起學習,共同進步~

文章內容

我們在之前使用過@ComponentScan結合@Controller、@Service、@Component、@Repository往Spring容器中註冊組件,也使用過實現ImportSelector和ImportBeanDefinitionRegistrar接口結合@Import往Spring容器中註冊組件。我們再來看一種使用FactoryBean往容器中註冊組件。


FactoryBean瞭解


先來看一下FactoryBean接口,我在下面的方法上加上註釋

<code>public interface FactoryBean {

    /**
     * 返回一個由該工廠管理的的Bean實例
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * 返回由該工廠管理的Bean的類型
     */
    @Nullable
    Class> getObjectType();

    /**
     * 返回該工廠管理的對象是否是單例
     * 這是一個default方法,默認返回true
     */
    default boolean isSingleton() {
        return true;
    }
}
/<code>

我們來實現以下這個接口試著註冊一個Bean。


FactoryBean使用


  • 我們來創建一個Grapes類,後面就將這個類註冊到Spring容器中
<code>package cn.nesive.spring.factorybean;

public class Grapes {}/<code>
  • 接著我們實現FactoryBean接口,將Grapes類註冊到Spring容器中
<code>package cn.nesive.spring.factorybean;

import org.springframework.beans.factory.FactoryBean;

public class GrapesFactoryBean implements FactoryBean<grapes> {


    @Override
    public Grapes getObject() throws Exception {
        return new Grapes();
    }

    @Override
    public Class> getObjectType() {
        return Grapes.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}/<grapes>/<code>
  • 創建一個配置類,並通過@Import註解將GrapesFactoryBean交由Spring管理
<code>package cn.nesive.spring.factorybean; 


import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(value = {GrapesFactoryBean.class})
public class FactoryBeanConfig {}/<code>
  • 看看此刻Spring容器中所包含的Bean實例都有那些,我們打印一下容器中所有的Bean定義信息
<code>package cn.nesive.spring.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class FactoryBeanTest {
    @Test
    public void test01(){
        ApplicationContext context = new AnnotationConfigApplicationContext(
                FactoryBeanConfig.class
        );
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}/<code>

運行結果:

<code>org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
factoryBeanConfig
cn.nesive.spring.factorybean.GrapesFactoryBean/<code>

我們發現此這裡並沒有我們想要的Grapes對象,那是怎麼回事呢? 原因就是cn.nesive.spring.factorybean.GrapesFactoryBean這個名稱實際上定義的就是Grapes對象。 那我們來瞅瞅~


Bean和BeanFactoryBean


<code>package cn.nesive.spring.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class FactoryBeanTest {
    @Test
    public void test01() throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(
                FactoryBeanConfig.class
        );
        Grapes factoryBean = (Grapes)context.getBean(
                "cn.nesive.spring.factorybean.GrapesFactoryBean"
        );
        // 查詢cn.nesive.spring.factorybean.GrapesFactoryBean的實例類型
        System.out.println(factoryBean.getClass());
        // 查看是否單例
        System.out.println(factoryBean == context.getBean(Grapes.class));
    }
}/<code>

運行結果:

<code>class cn.nesive.spring.factorybean.Grapes
true/<code>

那麼可以我們定義名稱為cn.nesive.spring.factorybean.GrapesFactoryBean的Bean實例實際上是cn.nesive.spring.factorybean.Grapes類型。並且它是單例的。

由於我們在配置類中使用Import導入的組件是GrapesFactoryBean。那麼我們想要獲取GrapesFactoryBean實例怎麼辦呢? 答案就是需要在cn.nesive.spring.factorybean.GrapesFactoryBean之前加上"&"符號。我們來看看BeanFatory接口的FACTORY_BEAN_PREFIX註釋信息倆看看,大概意思就是:

<code>用於取消對FactoryBean實例的引用,並將其與FactoryBean創建的bean區分開來。例如,如果名為myJndiObject的bean是FactoryBean,那麼獲取&myJndiObject將返回工廠,而不是工廠返回的實例。/<code> 

那我們嘗試一下在Spring容器中獲取工廠實例。


獲取FactoryBean實例

<code>package cn.nesive.spring.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class FactoryBeanTest {
    @Test
    public void test01() throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(
                FactoryBeanConfig.class
        );
        // 加上前綴"&",獲取工廠實例
        GrapesFactoryBean factoryBean = (GrapesFactoryBean)context.getBean(
                "&cn.nesive.spring.factorybean.GrapesFactoryBean"
        );
        System.out.println(factoryBean.getClass());
    }
}/<code>

來看看運行結果:

<code>class cn.nesive.spring.factorybean.GrapesFactoryBean/<code>

可以看到加上前綴"&"這個時候就返回了工廠實例。



分享到:


相關文章: