写在前面
FactoryBean有什么作用:
FactoryBean是以工厂形式生成Bean,在对Bean进行修饰之后返回Bean。
常用的使用场景为: 根据不同的配置类型返回不同类型的处理Bean,整体上简化了XML配置等。
Spring本身有70多个FactoryBean的实现,通过它隐藏了一些复杂的实现细节。
理解FactoryBean
举个例子,看看通过FactoryBean简化XML配置。
public class Student {
/** 姓名 */
private String name;
/** 年龄 */
private int age;
/** 班级名称 */
private String className;
}
实现FactoryBeen接口:
public class StudentFactoryBean implements FactoryBean<Student> {
private String studentInfo;
@Override
public Student getObject() throws Exception {
if (this.studentInfo == null) {
throw new IllegalArgumentException("'studentInfo' is required");
}
String[] splitStudentInfo = studentInfo.split(",");
if (null == splitStudentInfo || splitStudentInfo.length != 3) {
throw new IllegalArgumentException("'studentInfo' config error");
}
Student student = new Student();
student.setName(splitStudentInfo[0]);
student.setAge(Integer.valueOf(splitStudentInfo[1]));
student.setClassName(splitStudentInfo[2]);
return student;
}
@Override
public Class<?> getObjectType() {
return Student.class;
}
public void setStudentInfo(String studentInfo) {
this.studentInfo = studentInfo;
}
}
创建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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注意:class不是Student而是StudentFactoryBean-->
<bean id="student" class="com.lyc.cn.day03.StudentFactoryBean" p:studentInfo="张三,25,三年二班"/>
</beans>
测试:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("day03.xml");
System.out.println(applicationContext.getBean("student"));
System.out.println(applicationContext.getBean("&student"));
Student{name='张三', age=25, className='三年二班'}
org.springframework.beans.factory_bean.StudentFactoryBean@1ae369b7
这样就简化了通过BeanFactory接口简化配置XML的作业了。如果不加&
返回的是实例,加了返回的是工厂bean本身。
默认返回单例:
//实例是否单例模式,默认返回true
default boolean isSingleton() {
return true;
}
实现个性化输出Bean
通过FactoryBean个性化输出Bean。
public interface Animal {
void sayHello();
}
public class Cat implements Animal {
@Override
public void sayHello() {
System.out.println("hello, 喵喵喵...");
}
}
public class Dog implements Animal {
@Override
public void sayHello() {
System.out.println("hello, 汪汪汪...");
}
}
对于Animal 接口有两个实现:Cat和Dog。
新建AnimalFactorybean:
public class AnimalFactoryBean implements FactoryBean<Animal> {
private String animal;
@Override
public Animal getObject() throws Exception {
if (null == animal) {
throw new IllegalArgumentException("'animal' is required");
}
if ("cat".equals(animal)) {
return new Cat();
} else if ("dog".equals(animal)) {
return new Dog();
} else {
throw new IllegalArgumentException("animal type error");
}
}
@Override
public Class<?> getObjectType() {
if (null == animal) {
throw new IllegalArgumentException("'animal' is required");
}
if ("cat".equals(animal)) {
return Cat.class;
} else if ("dog".equals(animal)) {
return Dog.class;
} else {
throw new IllegalArgumentException("animal type error");
}
}
public void setAnimal(String animal) {
this.animal = animal;
}
}
增加XML配置:
<bean id="animal" class="com.lyc.cn.day03.AnimalFactoryBean" p:animal="cat"/>
测试:
public void testAnimalFactoryBean() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("day03.xml");
Animal animal = applicationContext.getBean("animal", Animal.class);
animal.sayHello();
}
---------------------
hello, 喵喵喵...