概述
我们日常基本的使用中对BeanFactory、FactoryBean、factory-method、facotry-bean基本上不需要关系,但是本着对技术的好奇、敬畏、面试的角度,我们还是要了解一下它们到底时什么,有什么用。以后在工作中可能会使用到哦。
BeanFactory
这个最容易理解,bean工厂,bean的工厂,其实就是我们日常说是的spring容器,所有被spring管理的bean都在其中。
FactoryBean
为什么要使用FactoryBean
我们有多种方式可以向Spring容器中注册bean。
可以使用@Configuration注解结合@Bean注解向Spring容器中注册bean;
可以按照条件向Spring容器中注册bean;
可以使用@Import注解向容器中快速导入bean对象;
可以在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean。
一般情况下,Spring是通过反射机制利用bean的class属性指定实现类来实例化bean的。
但是如果示例化bean的过程比较复杂,按照传统的方式需要在标签中提供大量的配置信息,配置方式的灵活性是受限的,如果能够采用编码的方式定制bean实例化,使用起来比较方便。
下面讲解如何使用FactoryBean向Spring容器中注册bean。
生产bean的工厂,可以理解为就是一个生成bean的代理类。是Spring的特殊接口,工厂类接口(FactoryBean),为了解决复杂的实例化bean过程而被创造的,新版本增加了泛型类应对所有类型。
public interface FactoryBean<T> {
T getObject() throws Exception; //返回由FactoryBean创建的Bean实例
Class<T> getObjectType();
boolean isSingleton();
}
通过这个接口,我们可以看出使用的就是工厂方法模式,不同的子类实现FactoryBean接口,生成具体的bean。
创建复杂bean时简化配置
spring中如果bean在多参数的情况下需要在中提供大量的配置信息。
例如:
public class Car {
private int maxSpeed ;
private String brand ;
private double price ;
//getter/setter方法省略...
}
<bean id ="car" class="xxx.Car">
<property name="maxSpeed" ref="100"/>
<property name="brand" ref="Suzuki"/>
<property name="price" ref="100000"/>
</bean>
可以看到当属性越多时,标签就越复杂。
当使用了FactoryBean作为工厂类来生产Car对象时:
// 工厂类,实现 FactoryBean<T>接口
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo ;
// 重写getObject()方法,创建Car实例
public Car getObject () throws Exception {
Car car = new Car () ;
// 将carInfo信息以逗号形式分割,分给各个属性,返回实例
String [] infos = carInfo.split ( "," ) ;
car.setBrand ( infos [ 0 ]) ;
car.setMaxSpeed ( Integer. valueOf ( infos [ 1 ])) ;
car.setPrice ( Double. valueOf ( infos [ 2 ])) ;
return car;
}
public Class<Car> getObjectType () {
return Car.class ;
}
public boolean isSingleton () {
return false ;
}
public String getCarInfo () {
return this.carInfo ;
}
// 接受逗号分割符设置属性信息
public void setCarInfo ( String carInfo ) {
this.carInfo = carInfo;
}
}
<bean id="car" class="com.baobaotao.factorybean.CarFactoryBean">
<property name="carInfo" value="法拉利,400,2000000"/>
</bean>
这样就极大的简化了标签的代码量,在配置多个bean,多参数的场景下很实用。
当调用getBean(“car”)时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用方法CarFactoryBean#getObject()方法返回Car实例。
如果希望获取CarFactoryBean的实例,则需要使用getBean(“&car”),这是spring的内部约定:在需要获取FactoryBean时需要在getBean(beanName)方法是在beanName前显示的加上&前缀。
getBean(“car”) -> Car实例;
getBean(“&car”) -> CarFactoryBean实例;
简化依赖
当有其他类想要依赖Car类时:
public class Person {
private Car car ;
private void setCar(Car car){ this.car = car; }
}
// 这里用java config代替了<bean>标签,但这不是重点
@Configuration
public class CarConfiguration {
@Bean
public CarFactoryBean carFactoryBean(){
CarFactoryBean cfb = new CarFactoryBean();
cfb.setBrand("Honda");
cfb.setPiece(1984000);
return cfb;
}
@Bean
public Person aPerson(){
Person person = new Person();
// 注意这里的不同,这里直接调用carFactoryBean().getObject()方法返回Car实例化对象
person.setCar(carFactoryBean().getObject());
return person;
}
}
小结
- BeanFactory:是个Factory,是SpringIOC容器,是对象的工厂。
- FactoryBean:是个Bean,一个能生产对象,修饰对象生产的工厂bean。
factory-method 与factory-bean
factory-method,factory-bean只有在spring中才有,springboot中不存在。
它们是标签的属性,用于创建bean对象,需要参数的话使用constructor-arg元素来指定它的参数。
factory-method可以用在静态方法创建类和非静态方法创建类两种,factory-bean用来指定创建bean的工厂bean,只能用在非静态方法创建bean的场景。
使用factory-method和factory-bean方式创建bean,我们可以自己定义一个类,然后在该类中定义一个方法,在该方法中完成spring bean的创建工作,其中factory-bean用于指定自己定义的类,factory-method用于指定创建bean的方法。
示例
- 定义要创建的bean
public class Stu {
public String stuId;
public Stu(String stuId) {
this.stuId = stuId;
}
}
- 定义工厂bean
public class StuFactory {
static Map<String,Stu> stuMap = new HashMap<>();
static{
//初始化
Stream.iterate(1,n->n+1).limit(5).map(String::valueOf).forEach(t-> stuMap.put(t, new Stu(t)));
}
//静态创建类,方法必须是静态(static修饰)
public static Stu getStaticStu(String stuId){
return stuMap.get(stuId);
}
//动态创建类
public Stu getDynamicStu(String stuId){
return new Stu(stuId);
}
}
定义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="staticStu" class="yudaosourcecode.factorymethod.StuFactory" factory-method="getStaticStu">
<!--传入getStaticStu方法的参数-->
<constructor-arg value="1"/>
</bean>
<!--生成对象的工厂-->
<bean id="stuFactory" class="yudaosourcecode.factorymethod.StuFactory"/>
<!--动态获取对象-->
<bean id="dynamicStu" factory-bean="stuFactory" factory-method="getDynamicStu">
<!--传入getDynamicStu方法的参数-->
<constructor-arg value="11"/>
</bean>
</beans>
- 测试
@Test
public void springFactoryMethodConfig() {
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:springFactoryMethodConfig.xml");
//获取静态Bean
Stu staticStu = ac.getBean("staticStu", Stu.class);
System.out.println("staticStu: ");
System.out.println(staticStu);
//获取动态Bean
Stu dynamicStu = ac.getBean("dynamicStu", Stu.class);
System.out.println("dynamicStu: ");
System.out.println(dynamicStu);
}
staticStu:
yudaosourcecode.factorymethod.Stu@6ec8211c
dynamicStu:
yudaosourcecode.factorymethod.Stu@7276c8cd
Process finished with exit code 0
参考
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99906.html