1.简介
在初学Spring时,大家可能混淆Spring中的两个接口,FactoryBean和BeanFactory,我们先来看一下这两者的各自含义,再通过简单的例子说明一下FactoryBean的使用。
- BeanFactory:在前面的博客中已经做了大量的介绍,该接口是IoC容器的顶级接口,是IoC容器的最基础实现,也是访问Spring容器的根接口,负责对bean的创建,访问等工作
- FactoryBean:是一种工厂bean,可以返回bean的实例,我们可以通过实现该接口对bean进行额外的操作,例如根据不同的配置类型返回不同类型的bean,简化xml配置等;其在使用上也有些特殊,大家还记得BeanFactory中有一个字符常量String FACTORY_BEAN_PREFIX = "&"; 当我们去获取BeanFactory类型的bean时,如果beanName不加&则获取到对应bean的实例;如果beanName加上&,则获取到BeanFactory本身的实例;FactoryBean接口对应Spring框架来说占有重要的地位,Spring本身就提供了70多个FactoryBean的实现。他们隐藏了实例化一些复杂的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型。
上面的文字可能生涩难懂,我们通过两个例子才简单说明下FactoryBean的使用:
2.简化xml配置,隐藏细节
如果一个类有很多的属性,我们想通过Spring来对类中的属性进行值的注入,势必要在配置文件中书写大量属性配置,造成配置文件臃肿,那么这时可以考虑使用FactoryBean来简化配置
- 新建bean
package com.lyc.cn.day03; /** * @author: LiYanChao * @create: 2018-09-05 11:50 */ public class Student { /** 姓名 */ private String name; /** 年龄 */ private int age; /** 班级名称 */ private String className; public Student() { } public Student(String name, int age, String className) { this.name = name; this.age = age; this.className = className; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", className='" + className + '\'' + '}'; } }
- 实现FactoryBean接口
package com.lyc.cn.day03; import org.springframework.beans.factory.FactoryBean; /** * @author: LiYanChao * @create: 2018-09-05 11:49 */ 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; } }
- 新建day03.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是StudentFactoryBean而不是Student--> <bean id="student" class="com.lyc.cn.day03.StudentFactoryBean" p:studentInfo="张三,25,三年二班"/> </beans>
- 新建测试用例
package com.lyc.cn.day03; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author: LiYanChao * @create: 2018-09-05 11:59 */ public class MyTest { @Before public void before() { System.out.println("---测试开始---\n"); } @After public void after() { System.out.println("\n---测试结束---"); } @Test public void testStudentFactoryBean() { 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 ---测试结束---