`

Spring之FactoryBean 用法

阅读更多
概述
         Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean,这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象。在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现,下面简单分析FactoryBean的用法。

2.实例
以下SimpleFactoryBean类实现了FactoryBean接口中的三个方法。 并将该类配置在XML中。
Java代码  收藏代码
public class SimpleFactoryBean implements FactoryBean { 
        private boolean flag; 
     
        public Object getObject() throws Exception { 
            if (flag) { 
                return new Date(); 
            } 
            return new String("false"); 
        } 
     
        @SuppressWarnings("unchecked") 
        public Class getObjectType() { 
            return flag ? Date.class : String.class; 
        } 
     
        public boolean isSingleton() { 
            return false; 
        } 
     
        public void setFlag(boolean flag) { 
            this.flag = flag; 
        } 
    } 
     
    <bean id="factoryBeanOne" class="com.study.demo.factorybean.SimpleFactoryBean" > 
        <property name="flag"> 
            <value>true</value> 
        </property> 
    </bean> 
     
    <bean id="factoryBeanTwo" class="com.study.demo.factorybean.SimpleFactoryBean" > 
        <property name="flag"> 
            <value>false</value> 
        </property> 
    </bean> 
     
    public class MainTest { 
        public static void main(String[] args) { 
            Resource res = new ClassPathResource("bean.xml"); 
            BeanFactory factory = new XmlBeanFactory(res); 
            System.out.println(factory.getBean("factoryBeanOne").getClass()); 
            System.out.println(factory.getBean("factoryBeanTwo").getClass()); 
        } 
    } 


通过简单的测试可知,该类输出如下:
class java.util.Date
class java.lang.String
也就是说,容器通过getBean方法返回的不是FactoryBean本身,而是FactoryBean实现类中getObject()方法所返回的对象。

3.FactoryBean的扩展应用
以Spring集成 ehcache 为例,看下org.springframework.cache.ehcache.EhCacheManagerFactoryBean类与org.springframework.cache.ehcache.EhCacheFactoryBean类。EhCacheManagerFactoryBean类中的getObject()和getObjectType() 方法返回的如下:
Java代码  收藏代码
public Object getObject() { 
            return this.cacheManager; 
        } 
     
    public Class getObjectType() { 
            return (this.cacheManager != null ? this.cacheManager.getClass() : CacheManager.class); 
        } 


EhCacheFactoryBean类中的getObject()和getObjectType() 方法返回的如下:
Java代码  收藏代码
public Object getObject() { 
            return this.cache; 
        } 
     
        public Class getObjectType() { 
            return (this.cache != null ? this.cache.getClass() : Ehcache.class); 
        } 

有了这两个FactoryBean,在Spring容器中使用ehcache就变得很简单了。配置如下:
Java代码  收藏代码
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">   
              <property name="configLocation">   
              <value>classpath:ehcache.xml</value>   
              </property>   
        </bean>   
     
        <bean id="levelOneCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">   
              <property name="cacheManager">   
                    <ref local="cacheManager" />   
              </property>   
              <property name="cacheName">   
                    <value>levelOneCache</value>   
              </property>   
        </bean> 

应用代码如下:
Java代码  收藏代码
public class MainTest { 
            public static void main(String[] args) { 
                Resource res = new ClassPathResource("bean.xml"); 
                BeanFactory factory = new XmlBeanFactory(res); 
                //取到CacheManager类的实例  
                CacheManager cacheManager = (CacheManager) factory 
                        .getBean("cacheManager"); 
                //取到Cache类的实例  
                Cache levelOneCache = cacheManager.getCache("levelOneCache"); 
            } 
        } 
         


=================================================================================




首先要分辨BeanFactory 与 FactoryBean的区别, 两个名字很像,所以容易搞混

BeanFactory: 以Factory结尾,表示它是一个工厂类,是用于管理Bean的一个工厂

FactoryBean:以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的Id从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身, 如果要获取FactoryBean对象,可以在id前面加一个&符号来获取。


Spring中的Bean有两种。

一种是普通的bean ,比如配置

[html] view plaincopy
<bean id="personService" class="com.spring.service.impl.PersonServiceImpl" scope="prototype"> 
            <property name="name" value="is_zhoufeng" /> 
      </bean>   
那个使用BeanFactory根据id personService获取bean的时候,得到的对象就是PersonServiceImpl类型的。

另外一种就是实现了org.springframework.beans.factory.FactoryBean<T>接口的Bean , 那么在从BeanFactory中根据定义的id获取bean的时候,获取的实际上是FactoryBean接口中的getObject()方法返回的对象。

以Spring提供的ProxyFactoryBean为例子,配置如下:

[html] view plaincopy
<bean id="personServiceByLog" class="org.springframework.aop.framework.ProxyFactoryBean"> 
            <property name="proxyInterfaces"> 
                <list> 
                    <value>com.spring.service.PersonService</value> 
                </list> 
            </property> 
            <property name="interceptorNames"> 
                <list> 
                    <value>logInteceptor</value> 
                    <value>ZFMethodAdvice</value> 
                </list> 
            </property> 
            <property name="targetName" value="personService" />   
     </bean> 

那么在代码中根据personServiceByLog来获取的Bean实际上是PersonService类型的。
[java] view plaincopy
@Test 
public void test01() { 
 
     PersonService ps = context.getBean("personService", PersonService.class); 
 
     ps.sayHello(); 
 
     String name = ps.getName(); 
 
     System.out.println(name); 


如果要获取ProxyFactoryBean本身,可以如下
[java] view plaincopy
@Test 
public void test04() { 
     ProxyFactoryBean factoryBean = context.getBean("&personServiceByLog", ProxyFactoryBean.class); 
     PersonService ps = (PersonService) factoryBean.getObject(); 
     String name = ps.getName(); 
     System.out.println(name); 
 





自己实现一个FactoryBean, 功能:用来代理一个对象,对该对象的所有方法做一个拦截,在方法调用前后都输出一行log

[java] view plaincopy
package com.spring.factorybean; 
 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
 
import org.springframework.beans.factory.DisposableBean; 
import org.springframework.beans.factory.FactoryBean; 
import org.springframework.beans.factory.InitializingBean; 
 
public class ZFFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean { 
 
    // 被代理对象实现的接口名(在使用Proxy时需要用到,用于决定生成的代理对象类型) 
    private String interfaceName; 
 
    // 被代理的对象 
    private Object target; 
 
    // 生成的代理对象 
    private Object proxyObj; 
 
    public void destroy() throws Exception { 
        System.out.println("distory..."); 
    } 
 
    public void afterPropertiesSet() throws Exception { 
 
        proxyObj = Proxy.newProxyInstance(this.getClass().getClassLoader(), 
                                          new Class[] { Class.forName(interfaceName) }, new InvocationHandler() { 
 
                                              public Object invoke(Object proxy, Method method, Object[] args) 
                                                                                                              throws Throwable { 
                                                  System.out.println("method:" + method.getName()); 
                                                  System.out.println("Method before..."); 
                                                  Object result = method.invoke(target, args); 
                                                  System.out.println("Method after..."); 
                                                  return result; 
                                              } 
                                          }); 
 
        System.out.println("afterPropertiesSet"); 
    } 
 
    public Object getObject() throws Exception { 
        System.out.println("getObject"); 
        return proxyObj; 
    } 
 
    public Class<?> getObjectType() { 
        return proxyObj == null ? Object.class : proxyObj.getClass(); 
    } 
 
    public boolean isSingleton() { 
        return true; 
    } 
 
    public String getInterfaceName() { 
        return interfaceName; 
    } 
 
    public void setInterfaceName(String interfaceName) { 
        this.interfaceName = interfaceName; 
    } 
 
    public Object getTarget() { 
        return target; 
    } 
 
    public void setTarget(Object target) { 
        this.target = target; 
    } 
 


然后来试试:
首先这样定义bean

[java] view plaincopy
<bean id="personService" class="com.spring.service.impl.PersonServiceImpl" scope="prototype"> 
            <property name="name" value="is_zhoufeng" /> 
      </bean>   
       
      <bean id="zfPersonService" class="com.spring.factorybean.ZFFactoryBean"> 
        <property name="interfaceName" value="com.spring.service.PersonService" /> 
        <property name="target"  ref="personService"/> 
      </bean> 
然后获取Bean,并测试。
[java] view plaincopy
@Test 
public void test06() { 
     PersonService ps = context.getBean("zfPersonService", PersonService.class); 
 
     ps.sayHello(); 
 
     String name = ps.getName(); 
 
     System.out.println(name); 


会发现sayHello与getName方法调用前后都有log打印。


上面的ZFBeanFactory只是模仿了ProxyFactoryBean的功能做了一个实现而已。

其实通过FactoryBean这种特点,可以实现很多有用的功能 。。。

分享到:
评论

相关推荐

    spring的FactoryBean增强我们的目标对象.rar

    通过FactoryBean在获取目标类的时间我们将增强的代理类给返回,使得我们调用方法的时间使用的代理类来增强,如果需要继续使用未代理的对象,则直接@Autowired 注入使用.

    spring中FactoryBean中的getObject()方法实例解析

    主要介绍了spring中FactoryBean中的getObject()方法实例解析,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

    spring的详细介绍

    Spring介绍 1. Spring 2. 使用spring的主要目的 3. Spring的模块 Ejb容器(以前是) Ioc容器(现在的控制权) 控制反转Ioc(Invertion of control)依赖注入(Dependency Injection) ...13. 接口FactoryBean的使用

    Spring-Reference_zh_CN(Spring中文参考手册)

    3.7.3. 使用FactoryBean定制实例化逻辑 3.8. ApplicationContext 3.8.1. 利用MessageSource实现国际化 3.8.2. 事件 3.8.3. 底层资源的访问 3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的...

    尚硅谷佟刚Spring4代码及PPT.rar

    在 Eclipse 中安装 SpringIDE 插件、IOC & DI、在 Spring 中配置 Bean、自动装配、Bean 之间的关系(依赖、继承)、Bean 的作用域、使用外部属性文件、SpEL、管理 Bean 的生命周期、通过工厂方法配置 Bean、通过 ...

    Spring 2.0 开发参考手册

    3.7.3. 使用FactoryBean定制实例化逻辑 3.8. ApplicationContext 3.8.1. 利用MessageSource实现国际化 3.8.2. 事件 3.8.3. 底层资源的访问 3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕...

    Spring.3.x企业应用开发实战(完整版).part2

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    Spring攻略(第二版 中文高清版).part1

    1.7 使用Spring的FactoryBean创建Bean 27 1.7.1 问题 27 1.7.2 解决方案 27 1.7.3 工作原理 27 1.8 使用工厂Bean和Utility Schema定义集合 29 1.8.1 问题 29 1.8.2 解决方案 29 1.8.3 工作原理 29 ...

    Spring中文帮助文档

    3.7.3. 使用FactoryBean定制实例化逻辑 3.8. The ApplicationContext 3.8.1. BeanFactory 还是 ApplicationContext? 3.8.2. 利用MessageSource实现国际化 3.8.3. 事件 3.8.4. 底层资源的访问 3.8.5. ...

    spring chm文档

    3.7.3. 使用FactoryBean定制实例化逻辑 3.8. ApplicationContext 3.8.1. 利用MessageSource实现国际化 3.8.2. 事件 3.8.3. 底层资源的访问 3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕...

    Spring API

    3.7.3. 使用FactoryBean定制实例化逻辑 3.8. The ApplicationContext 3.8.1. BeanFactory 还是 ApplicationContext? 3.8.2. 利用MessageSource实现国际化 3.8.3. 事件 3.8.4. 底层资源的访问 3.8.5. ...

    Spring攻略(第二版 中文高清版).part2

    1.7 使用Spring的FactoryBean创建Bean 27 1.7.1 问题 27 1.7.2 解决方案 27 1.7.3 工作原理 27 1.8 使用工厂Bean和Utility Schema定义集合 29 1.8.1 问题 29 1.8.2 解决方案 29 1.8.3 工作原理 29 ...

    Spring3.x企业应用开发实战(完整版) part1

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    spring源码解决

    //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象, //如果需要得到工厂本身,需要转义 String FACTORY_BEAN_PREFIX = "&"; //这里根据bean的名字,在IOC容器中...

    spring aop 实现源代码--xml and annotation(带lib包)

    下面通过例子来说明Before Advice的使用方法。首先定义目标对象所要实现的接口: java 代码 1. package com.savage.aop 2. 3. public interface MessageSender { 4. void send(String message); 5. } 接着...

    Spring 3 Reference中文

    4.8.3 使用FactoryBean 来自定义实例化逻辑. 84 4.9 基于注解的容器配置. 85 4.9.1 @Required.. 86 4.9.2 @Autowired和@Inject.. 86 4.9.3 使用限定符来微调基于注解的自动装配 89 4.9.4 ...

    spring:这是Spring框架研究

    spring This is spring framework study ...八、使用spring FactoryBean技术模拟mybatis MapperScan注解 https://github.com/AvengerEug/spring/tree/develop/implement-mapperscan 九、mybatis源码学习 ...

    Spring面试题

    FactoryBean 接口为使用 Spring 框架构建的应用程序添加了一个间接的级别。 IOC 示例 理解控制反转最简单的方式就是看它的实际应用。在对由三部分组成的 Spring 系列 的第 1 部分进行总结时,我使用了一个示例,...

    spring3.1中文参考文档

    spring3.1中文参考文档,南磊翻译,现在有4章,目录如下: 第一部分 Spring framework概述.......................................................................................................................

    spring学习资料

    3. //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象, 4. //如果需要得到工厂本身,需要转义 5. String FACTORY_BEAN_PREFIX = "&"; 6. 7. //这里根据...

Global site tag (gtag.js) - Google Analytics