Spring之FactoryBean

Spring之FactoryBean

首先要分辨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 plain copy

  1. <bean id="personService" class="com.spring.service.impl.PersonServiceImpl" scope="prototype">
  2. <property name="name" value="is_zhoufeng" />
  3. </bean>

那个使用BeanFactory根据id personService获取bean的时候,得到的对象就是PersonServiceImpl类型的。

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

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

[html] view plain copy

  1. <bean id="personServiceByLog" class="org.springframework.aop.framework.ProxyFactoryBean">
  2. <property name="proxyInterfaces">
  3. <list>
  4. <value>com.spring.service.PersonService</value>
  5. </list>
  6. </property>
  7. <property name="interceptorNames">
  8. <list>
  9. <value>logInteceptor</value>
  10. <value>ZFMethodAdvice</value>
  11. </list>
  12. </property>
  13. <property name="targetName" value="personService" />
  14. </bean>

那么在代码中根据personServiceByLog来获取的Bean实际上是PersonService类型的。

[java] view plain copy

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

如果要获取ProxyFactoryBean本身,可以如下

[java] view plain copy

  1. @Test
  2. public void test04() {
  3. ProxyFactoryBean factoryBean = context.getBean("&personServiceByLog", ProxyFactoryBean.class);
  4. PersonService ps = (PersonService) factoryBean.getObject();
  5. String name = ps.getName();
  6. System.out.println(name);
  7. }

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

[java] view plain copy

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

然后来试试:

首先这样定义bean

[java] view plain copy

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

然后获取Bean,并测试。

[java] view plain copy

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

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

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

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

时间: 2024-11-04 16:27:21

Spring之FactoryBean的相关文章

Spring错误——Spring 注解——factory-bean reference points back to the same bean definition

背景:学习Spring,在使用注解@Bean的name属性配置<bean>实例时,不能注册实例成功 报错 WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'config

Spring中FactoryBean的作用和实现原理

BeanFactory与FactoryBean,相信很多刚翻看Spring源码的同学跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的.BeanFactory是Spring中Bean工厂的顶层接口,也是我们常说的SpringIOC容器,它定下了IOC容器的一些规范和常用方法并管理着Spring中所有的Bean,今天我们不讲它,我们看一下后面那个FactoryBean. 先说下FactoryBean和其作用再开始分析:首先它是一个Bean,但又不仅仅是一个Bean.它是一个能生产或修饰对象生成的

Spring初学之FactoryBean配置Bean

实体bean: Car.java: package spring.beans.factorybean; public class Car { private String name; private int price; public Car(String name, int price) { super(); this.name = name; this.price = price; } public String getName() { return name; } public void

spring中的工厂(二)FactoryBean

工厂bean是Spring中的特殊Bean,工厂bean必须要实现FactoryBean接口.FaCtoryBean接口是工厂Bean的标准接口.Factorybean提供以下三个方法, T getObject():实现该方法负责返回该工厂Bean生成的Java实例. Class<?> getObjectType():实现该方法返回该工厂Bean生成的Java实例的实现类 boolean isSingleton():实现该方法表示工厂Bean生成的java实例是否是单利模式的.  程序通过ge

spring之通过FactoryBean配置Bean

Car.java package com.gong.spring.beans.factoryBean; public class Car { private String name; private double price; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price;

Mybatis整合Spring 【转】

根据官方的说法,在ibatis3,也就是Mybatis3问世之前,Spring3的开发工作就已经完成了,所以Spring3中还是没有对Mybatis3的支持.因此由Mybatis社区自己开发了一个Mybatis-Spring用来满足Mybatis用户整合Spring的需求.下面就将通过Mybatis-Spring来整合Mybatis跟Spring的用法做一个简单的介绍. MapperFactoryBean 首先,我们需要从Mybatis官网上下载Mybatis-Spring的jar包添加到我们项

Spring_通过 FactoryBean 配置 Bean

beans-factorybean.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" xsi:schemaLocation="http://w

osgi与流行的框架(spring,struts,hibernate等)的集成

1.与流行的 JAVA B/S体系架构的集成 了解了基于osgi系统设计的基本思想,进一步来研究osgi与流行的框架(spring,struts,hibernate等)的集成,这里首先讲解一下集成原理. l        解决和spring的集成 由于spring的应用占据了大部分的java应用领域,所以解决与spring的集成是osgi必须解决的,spring-dm的推出大大促进了两者的结合,有助于osgi进军企业领域. Spring所带来得好处主要有这么两点: 1.       不需要对外的

Spring之单元测试

引言 是否在程序运行时使用单元测试是衡量一个程序员素质的一个重要指标.使用单元测试既可以让我检查程序逻辑的正确性还可以让我们减少程序测试的BUG,便于调试可以提高我们写程序的效率.以前我们做单元测试的时候使用的都是JUnit,只需要引入相关的jar包即可.可是我们在使用Spring的时候是不是也可以使用单元测试呢,答案是肯定的.Spring自己整合了JUint,极大的方便了我们的程序开发. 1.引入相关环境 如果我们想要使用Spring提供的单元测试功能,我们除了引入Spring的相关环境我们还