首页 > 技术文章 > Spring的FactoryBean

qiyu 2017-07-06 21:03 原文

 首先是BeanFactory和FactoryBean的区别:

  • FactoryBean:是一个Java Bean,但是它是一个能生产对象的工厂Bean,它的实现和工厂模式及修饰器模式很像。比如下:我们把bean比作猪,那么FactoryBean可以算是一个母猪,首先它本身也是一只猪,但它能够下小猪。
  • BeanFactory:这就是一个Factory,是一个IOC容器或者叫对象工厂,它里面存着很多的bean。还用上面那个比如:如果bean是猪,那么它可以理解成猪圈,猪圈里面有很

FactoryBean的核心就在于通过getObject方法可以获取的是它所生产的对象

实现FactoryBean 必须实现接口的3个方法:getObject、getObjectType、isSingleton

使用FactoryBean的场景有两个:1、创建代理对象 2、通过xml配置方式比较繁琐或有难度,那么可以通过FactoryBean 在java代码里面配置bean

网上找了两个例子,说明这两点

1.创建代理对象的例子:

ZFFactoryBean 
 1 package com.spring.factorybean;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 import org.springframework.beans.factory.DisposableBean;
 8 import org.springframework.beans.factory.FactoryBean;
 9 import org.springframework.beans.factory.InitializingBean;
10 
11 public class ZFFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {
12 
13     // 被代理对象实现的接口名(在使用Proxy时需要用到,用于决定生成的代理对象类型)
14     private String interfaceName;
15 
16     // 被代理的对象
17     private Object target;
18 
19     // 生成的代理对象
20     private Object proxyObj;
21 
22     public void destroy() throws Exception {
23         System.out.println("distory...");
24     }
25 
26     public void afterPropertiesSet() throws Exception {
27 
28         proxyObj = Proxy.newProxyInstance(this.getClass().getClassLoader(),
29                                           new Class[] { Class.forName(interfaceName) }, new InvocationHandler() {
30 
31                                               public Object invoke(Object proxy, Method method, Object[] args)
32                                                                                                               throws Throwable {
33                                                   System.out.println("method:" + method.getName());
34                                                   System.out.println("Method before...");
35                                                   Object result = method.invoke(target, args);
36                                                   System.out.println("Method after...");
37                                                   return result;
38                                               }
39                                           });
40 
41         System.out.println("afterPropertiesSet");
42     }
43 
44     public Object getObject() throws Exception {
45         System.out.println("getObject");
46         return proxyObj;
47     }
48 
49     public Class<?> getObjectType() {
50         return proxyObj == null ? Object.class : proxyObj.getClass();
51     }
52 
53     public boolean isSingleton() {
54         return true;
55     }
56 
57     public String getInterfaceName() {
58         return interfaceName;
59     }
60 
61     public void setInterfaceName(String interfaceName) {
62         this.interfaceName = interfaceName;
63     }
64 
65     public Object getTarget() {
66         return target;
67     }
68 
69     public void setTarget(Object target) {
70         this.target = target;
71     }
72 
73 }

PersonService 和 PersonServiceImpl的代码此处省略

xml配置:

1  <bean id="personService" class="com.spring.service.impl.PersonServiceImpl" scope="prototype">
2                <property name="name" value="is_zhoufeng" />
3        </bean>  
4        
5        <bean id="zfPersonService" class="com.spring.factorybean.ZFFactoryBean">
6             <property name="interfaceName" value="com.spring.service.PersonService" />
7             <property name="target"  ref="personService"/>
8        </bean>

用法:

 1    @Test
 2     public void test06() {
 3         PersonService ps = context.getBean("zfPersonService", PersonService.class);
 4 
 5         ps.sayHello();
 6 
 7         String name = ps.getName();
 8 
 9         System.out.println(name);
10     }

2.配置较为复杂的bean

Person类,get set省略

1 public class Person {  
2     private String name;  
3     private String address;  
4     private int age;  
5 }  

如果用xml配置,如下,会比较麻烦:

1 <bean id="personBean" class="com.gh.MavenTest.Person">  
2     <property name="name" value="gh1" />  
3     <property name="address" value="address1" />  
4     <property name="age" value="28" />  
5 </bean>  

换成FactoryBean的方式配置:

 1 public class PersonFactoryBean implements FactoryBean<Person>{  
 2       
 3     private String personInfo;  
 4       
 5     public Person getObject() throws Exception {  
 6         Person person =  new  Person () ;      
 7         String []  infos =  personInfo.split ( "," ) ;  
 8         person.setName(infos[0]);  
 9         person.setAddress(infos[1]);  
10         person.setAge(Integer.parseInt(infos[2]));  
11         return person;  
12     }  
13   
14     public Class<Person> getObjectType() {  
15         return Person.class;  
16     }  
17   
18     public boolean isSingleton() {  
19         return true;  
20     }  
21 }  

xml再配置一下:

1 <bean id="personFactory" class="com.hik.MavenTest.PersonFactory">  
2     <property name="personInfo" value="gh2,address2,22"></property>  
3 </bean> 

那么这个时候我们getBean("personFactory")得到的就是Person对象而不是PersonFactoryBean对象

如果要取到PersonFactoryBean这个bean, 在beanName前面加上&,即getBean("&personFactory")

spring自带了不少FactoryBean的实现,最下面是我们所在的公司的实现

 

具体使用的时候,还可以用FactoryBean创建多个bean

1 <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
2 <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
3 <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
4 <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
5 <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />

 

推荐阅读