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 ---測試結束---