BeanFactory是接口,提供了IOC容器最基本的形式,給具體的IOC容器的實現提供了規范
FactoryBean也是接口,為IOC容器中Bean的實現提供了更加靈活的方式,FactoryBean在IOC容器的基礎上給Bean的實現加上了一個簡單工廠模式和裝飾模式, 我們可以在getObject()方法中靈活配置。其實在Spring源碼中有很多FactoryBean的實現類.
區別:BeanFactory是個Factory,也就是IOC容器或對象工廠,FactoryBean是個Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)來進行管理的。但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式類似
1、 BeanFactory
BeanFactory,以Factory結尾,表示它是一個工廠類(接口), 它負責生產和管理bean的一個工廠。在Spring中,BeanFactory是IOC容器的核心接口,它的職責包括:實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。BeanFactory只是個接口,並不是IOC容器的具體實現,但是Spring容器給出了很多種實現,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一個,該實現將以XML方式描述組成應用的對象及對象間的依賴關系。
package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanFactory { /**
用於區分factoryBean和bean,后面會講到
*/ String FACTORY_BEAN_PREFIX = "&"; /** 返回byName返回bean的實例*/ Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; /** * Return a provider for the specified bean, allowing for lazy on-demand retrieval * of instances, including availability and uniqueness options. * @param requiredType type the bean must match; can be an interface or superclass * @return a corresponding provider handle * @since 5.1 * @see #getBeanProvider(ResolvableType) */ <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType); <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType); /** 判斷工廠中是否包含給定名稱的bean定義,若有則返回true*/ boolean containsBean(String name); /** 判斷bean是否為單例*/ boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /** 判斷bean是否為多例*/ boolean isPrototype(String name) throws NoSuchBeanDefinitionException; /** 檢查具有給定名稱的bean是否匹配指定的類型。 */ boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; /** 返回給定名稱的bean的Class,如果沒有找到指定的bean實例,則排除*/ @Nullable Class<?> getType(String name) throws NoSuchBeanDefinitionException; /** 返回給定bean名稱的所有別名 */ String[] getAliases(String name); }
2、FactoryBean
一般情況下,Spring通過反射機制利用<bean>的class屬性指定實現類實例化Bean,在某些情況下,實例化Bean過程比較復雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置信息。配置方式的靈活性是受限的,這時采用編碼的方式可能會得到一個簡單的方案。Spring為此提供了一個org.springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定制實例化Bean的邏輯。FactoryBean接口對於Spring框架來說占用重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了實例化一些復雜Bean的細節,給上層應用帶來了便利。從Spring3.0開始,FactoryBean開始支持泛型,即接口聲明改為FactoryBean<T>的形式
以Bean結尾,表示它是一個Bean,不同於普通Bean的是:它是實現了FactoryBean<T>接口的Bean,根據該Bean的ID從BeanFactory中獲取的實際上是FactoryBean的getObject()返回的對象,而不是FactoryBean本身,如果要獲取FactoryBean對象,請在id前面加一個&符號來獲取。
例如:我定義了一個Car類{Name,Color...等等屬性},我需要spring容器對其初始化
public class Car { private String Name; private String color; public String getName() { return Name; } public void setName(String name) { Name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Car{" + "Name='" + Name + '\'' + ", color='" + color + '\'' + '}'; } }
方法一:通過spring的xml的方式對其進行配置.
方法二:定義一個CarProxy類,實現factoryBean接口.
public class CarProxy implements FactoryBean<Car> { private String msg; private Car car;
//重寫getObject方法,返回car實例 @Override public Car getObject() throws Exception { Car car = new Car(); String[] magArr = msg.split(","); car.setName(magArr[0]); car.setColor(magArr[1]); this.car = car; return car; } @Override public Class<?> getObjectType() { return this.getClass()==null?car.getClass():this.getClass(); } public void setMsg(String msg) { this.msg = msg; } }
xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="cn.cg.beanFactory.CarProxy"> <property name="msg" value="法拉利,紅色" /> </bean> </beans>
test:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyTest { @Autowired private ApplicationContext ac; @Test public void fun1(){ //car Car car = (Car) ac.getBean("car"); System.out.println(car); } }
console:
Car{Name='法拉利', color='紅色'}
仔細觀察:"car"---->cn.cg.beanFactory.CarProxy
講道理ac.getBean("car");獲取的對象應該是CarProxy對象,但是我卻將該對象轉換成了Car對象,並且成功調用了其重寫的toString()方法???
因為當我們getBean時,spring對實現了FactoryBean接口的類實現了特殊處理
當調用getBean("car")時,Spring通過反射機制發現CarFactoryBean實現了FactoryBean的接口,
這時Spring容器就調用接口方法CarFactoryBean#getObject()方法返回。如果希望獲取CarFactoryBean的實例,
則需要在使用getBean(beanName)方法時在beanName前顯示的加上"&"前綴:如getBean("&car");
spring為什么要這樣設計
原因之一:
比如我們spring需要整合mybatis,在沒有spring-mybatis時(spring-mybatis會幫助你將MyBatis 代碼無縫地整合到Spring 中),
我們需要將mybatis核心類SqlSessionFactory注入到spring容器,那么思考使用最常用的兩種方式
(1)注解,可以mybatis是個獨立的項目.與spring無關,所以Pass!!!!
(2)xml,sqlSessionFacory需要注入許多的依賴,不方便的維護
所以可以選擇一個代理類去處理sqlSessionFacory,也就是我們在整合spring+mybatis時使用的SqlSessionFactoryBean
參考:https://www.cnblogs.com/aspirant/p/9082858.html