BeanFactory与FactoryBean
区别:BeanFactory是个Factory,也就是IOC容器或对象工厂,负责生产和管理bean, spring容器对该接口有多种实现,如:DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似,即可以自定义实现bean的实例化过程
生成一个普通的bean类
/**
* @author MM
* @create 2018-08-06 15:32
**/
public class Car {
String name;
public Car() {
}
public Car(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void run() {
System.out.println(this.name + " is running");
}
}
如果是直接通过BeanFactory实例化只需要简单配置
<bean id= "car" class = "com.deam.entity.Car">
<property name="name" value = "beanFactory"></property>
</bean>
然后通过spring容器实例化
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); BeanFactory factory = (BeanFactory) ctx; Car car1 = (Car) factory.getBean("car"); car1.run();
日志显示:
八月 06, 2018 4:43:56 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@17ed40e0: startup date [Mon Aug 06 16:43:56 CST 2018]; root of context hierarchy 八月 06, 2018 4:43:56 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [beans.xml] beanFactory is running Process finished with exit code 0
通过FactoryBean 实例化,创建一个bean实现FactoryBean接口重写getObject方法
/** * @author MM * @create 2018-08-06 16:29 **/ public class CarFactoryBean implements FactoryBean<Car> { String carInfo; public String getCarInfo() { return carInfo; } public void setCarInfo(String carInfo) { this.carInfo = carInfo; } @Nullable @Override public Car getObject() throws Exception { Car car = new Car(carInfo); return car; } @Nullable @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
配置容器实例化FactoryBean
<bean id="car" class="com.demo.util.CarFactoryBean">
<property name="carInfo" value="factoryBean"></property>
</bean>
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); BeanFactory factory = (BeanFactory) ctx; Car car1 = (Car) factory.getBean("car"); car1.run(); Car car2 = (Car) factory.getBean("car"); System.out.println("car1==car2 is " + (car1 == car2)); CarFactoryBean factoryBean = (CarFactoryBean) factory.getBean("&car"); System.out.println(factoryBean.getCarInfo());
日志显示:
八月 06, 2018 4:48:57 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@17ed40e0: startup date [Mon Aug 06 16:48:57 CST 2018]; root of context hierarchy 八月 06, 2018 4:48:57 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [beans.xml] factoryBean is running car1==car2 is false factoryBean
当调用getBean("car")时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean#getObject()方法返回。如果希望获取CarFactoryBean的实例,则需要在使用getBean(beanName)方法时在beanName前显示的加上"&"前缀:如getBean("&car");
1、FactoryBean与factory-bean的作用都是通过其他的一个bean工厂产生一个真实的bean,不同的是,FactoryBean是使用了spring默认的接口,具有一定侵入性,对框架造成依赖,factory-bean不会改变代码接口,属于注入方式。spring中很多类似的组队,比如init-method和InitializingBean。
2、从原则上,我们使用spring,很大的优点在于它没有侵略性。那么为什么会提供接口形式呢。接口形式更倾向于框架的使用,比如spirng的另一个重要的特性AOP,框架编写了AOPFactoryBean,我们不需要知道他内部实现,也不会获取他的实力,只需要配置它需要代理的类和接口,便可以成功返回一个真实的bean,也就是目标类的代理类,从而完成各种工作。
3、可以说spirng的很多扩展工作都是基于预留接口提供,同时新扩展的功能也会提供新的预留接口,比如aop的切面等。