1. 程式人生 > >理解spring中的BeanFactory和FactoryBean的區別與聯絡

理解spring中的BeanFactory和FactoryBean的區別與聯絡

首先,這倆都是個介面…

實現 BeanFactory 介面的類表明此類事一個工廠,作用就是配置、新建、管理 各種Bean。

而 實現 FactoryBean 的類表明此類也是一個Bean,型別為工廠Bean(Spring中共有兩種bean,一種為普通bean,另一種則為工廠bean)。顧名思義,它也是用來管理Bean的,而它本身由spring管理。

一個Bean想要實現 FactoryBean ,必須實現以下三個介面:

1. Object getObject():返回由FactoryBean建立的Bean的例項

2. boolean isSingleton():確定由FactoryBean建立的Bean的作用域是singleton還是prototype;

3.
getObjectType():返回FactoryBean建立的Bean的型別。

有一點需要注意,如果將一個實現了FactoryBean的類成功配置到了spring上下文中,那麼通過該類物件的名稱(比如appleFactoryBean)從spring的applicationContext或者beanFactory獲取bean時,獲取到的是appleFactoryBean建立的apple例項,而不是appleFactoryBean自己,如果想通過spring拿到appleFactoryBean,需要在名稱前加 & 符號 :

out.println(applicationContext.getBean
("&appleFactoryBean"))

這個prefix在BeanFactory介面原始碼中有提到:

/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";

還有一點需要注意,FactoryBean管理的bean實際上也是由spring進行配置、例項化、管理,因此由FactoryBean管理的bean不能再次配置到spring配置檔案中(xml、java類配置、註解均不可以),否則會報如下異常:

Exception in thread "main" org.springframework.beans.factory.BeanIsNotAFactoryException: Bean named 'appleFactoryBean' is expected to be of type 'org.springframework.beans.factory.FactoryBean' but was actually of type 'java.lang.Object'
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
    at com.joen.testspringcontainer.Start.main(Start.java:11)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

附上一個例子:

spring配置類:

@Configuration
@ComponentScan
public class Configurations {
}

AppleBean :

//@Component  這裡不可以加註解 !!!!!!
public class AppleBean{

}

AppleFactoryBean :

@Component
public class AppleFactoryBean implements FactoryBean{

    public Object getObject() throws Exception {
        return new AppleBean();
    }

    public Class<?> getObjectType() {
        return AppleBean.class;
    }

    public boolean isSingleton() {
        return false;
    }
}

啟動類 :

public class Start {
    public static void main(String[] args){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Configurations.class);
                 out.println(applicationContext.getBean("appleFactoryBean"));//得到的是apple
                 out.println(applicationContext.getBean("&appleFactoryBean"));//得到的是apple工廠
    }
}