spring 源码解读与设计详解:3 FactoryBean

上一篇文章讲到BeanFactory,BeanFactory是实现spring IOC原理实现的根接口,而本篇所讲的FactoryBean则是AOP原理实现的重要接口。

1. 先看FactoryBean的源码:

public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class<?> getObjectType();

	boolean isSingleton();

}

2. 下面简单讲一下FactoryBean相关概念。

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean,这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是该factoryBean的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象。如果要获取FactoryBean对象,可以在id前面加一个&符号来获取。            在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现。

Spring 框架中有很多FactoryBean   例如RmiProxyFactoryBean, SqlMapClientFactoryBean. LocalSessionFactoryBean等都是通过FactoryBean getObject方法驱动起来的.对bean的生产 修饰做了很好的封装。

3. 用几个例子来说明FactoryBean与普通bean的区别。

(1)普通bean

代码:

package spring.factorybean;

/**
 * @author Ding Chengyun
 * 2015-2-26
 */
public interface PersonService {

	public String getName();

	public String sayHello();

	public void setName(String name);
}<pre name="code" class="java">package spring.factorybean;

/**
 * @author Ding Chengyun
 * 2015-2-26
 */
public class PersonServiceImpl implements PersonService {
	public String name;

	/* (non-Javadoc)
	 * @see spring.PersonService#getName()
	 */
	@Override
	public String getName() {
		return name;
	}

	/* (non-Javadoc)
	 * @see spring.PersonService#sayHello()
	 */
	@Override
	public String sayHello() {
		System.out.println("sayHello");
		return "sayHello";
	}

	/* (non-Javadoc)
	 * @see spring.PersonService#setName()
	 */
	@Override
	public void setName(String name) {
		this.name = name;

	}
}

配置文件

<bean id="personService" class="spring.factorybean.PersonServiceImpl">
		<property name="name">
			<value>hello world</value>
		</property>
	</bean>

测试代码:

@Test
	 public void test02() {
		try {
			PersonService ps = context.getBean("personService", PersonService.class);
		    ps.sayHello();
		    String name = ps.getName();
		    System.out.println(name);
		} catch (Exception e) {
			e.printStackTrace();
		}
	 } 

(2)FactoryBean

代码:

package spring.factorybean;

import org.springframework.beans.factory.FactoryBean;

/**
 * @author Ding Chengyun
 * 2015-2-27
 */
public class MyFactoryBean implements FactoryBean<MyFactoryBeanImpl> {

	@Override
	public MyFactoryBeanImpl getObject() throws Exception {
		return new MyFactoryBeanImpl();
	}

	@Override
	public Class<?> getObjectType() {
		return MyFactoryBeanImpl.class;
	}

	@Override
	public boolean isSingleton() {
		return false;
	}

}<pre name="code" class="java">package spring.factorybean;

/**
 * @author Ding Chengyun
 * 2015-2-27
 */
public class MyFactoryBeanImpl {

}

配置文件

<bean id="myFactoryBean" class="spring.factorybean.MyFactoryBean"></bean>

测试代码:

@Test
	 public void test04() {
		try {
			MyFactoryBeanImpl bean = context.getBean("myFactoryBean", MyFactoryBeanImpl.class);
		    System.out.println(bean);  

		    MyFactoryBean factoryBean = context.getBean("&myFactoryBean", MyFactoryBean.class);
		    System.out.println(factoryBean); 

		    bean = (MyFactoryBeanImpl) factoryBean.getObject();
		    System.out.println(bean);
		} catch (Exception e) {
			e.printStackTrace();
		}
	 } 

4. 自定义一个FactoryBean,用来代理一个对象,对该对象的所有方法做一个拦截,在方法调用前后都输出一行log.

代码:

package 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;

/**
 * @author Ding Chengyun
 * 2015-2-27
 */
public class MyLogFactoryBean implements FactoryBean<Object>, InitializingBean,
		DisposableBean {
	// 被代理对象实现的接口名(在使用Proxy时需要用到,用于决定生成的代理对象类型)
    private String interfaceName;  

    // 被代理的对象
    private Object target;  

    // 生成的代理对象
    private Object proxyObj;  

	@Override
	public void destroy() throws Exception {
		 System.out.println("distory...");
	}

	@Override
	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;
					}
				});
	}

	@Override
	public Object getObject() throws Exception {
        return proxyObj;
	}

	@Override
	public Class<?> getObjectType() {
		return proxyObj == null ? Object.class : proxyObj.getClass();
	}

	@Override
	public boolean isSingleton() {
		return false;
	}

	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 id="myLogFactoryBean" class="spring.factorybean.MyLogFactoryBean">
        <property name="interfaceName" value="spring.factorybean.PersonService" />
        <property name="target"  ref="personService"/>
      </bean>

测试代码:

 @Test
	 public void test05() {
	     PersonService ps = context.getBean("myLogFactoryBean", PersonService.class);  

	     ps.sayHello();  

//	     String name = ps.getName();  

//	     System.out.println(name);
	 }
	 
时间: 2024-10-09 09:31:45

spring 源码解读与设计详解:3 FactoryBean的相关文章

spring 源码解读与设计详解:2 BeanFactory

在spring的官网中我们看到,spring的产品已经发展的非常壮大,然而很多产品对于很多公司来讲用的非常少,甚至用不到.因此本系列的源码解读也不会涉及全部的spring的产品.而是只对spring的核心功能IoC和AOP进行解释. 所谓源码解读,解读的是什么?实际上源码解读读的更多的是源码的注释,因为一个类的作用.一个接口或者一个方法的作用,我们往往是要根据注释才知道,这也是为什么在代码规范中,注释是一个非常重要的模块的原因. 参考: Spring源码分析--BeanFactory体系之接口详

Spark Streaming源码解读之Job详解

一:Spark Streaming Job生成深度思考 1. 做大数据例如Hadoop,Spark等,如果不是流处理的话,一般会有定时任务.例如10分钟触发一次,1个小时触发一次,这就是做流处理的感觉,一切不是流处理,或者与流处理无关的数据都将是没有价值的数据,以前做批处理的时候其实也是隐形的在做流处理. 2. JobGenerator构造的时候有一个核心的参数是jobScheduler, jobScheduler是整个作业的生成和提交给集群的核心,JobGenerator会基于DStream生

Spring源码解读之XmlBeanFactory

首先感谢<Spring源码深度解析>郝佳.接下来的Spring源码解读系列,都是读了郝佳的书后的观后感.再次感谢他,带我走进了源码的世界. BeanFactory factory= new XmlBeanFactory (new ClassPathResource("D:\\Project\\Eclipse\\Spring_Maven\\src\\main\\resources\\spring_beans.xml" )); new ClassPathResource(Str

Spring源码解读之核心容器上节

Spring架构图 说明 Spring的流行程度就不用我来说了,相信大家如果使用JAVA开发就一定知道它.写这篇文章的初衷在于:1.了解Spring底层实现原理,提升对Spring的认识与理解.2.学习优秀框架编程实现,学习优秀的设计模式.3.使用Spring三年多,对于底层细节希望知道更多,便于求职. 对于Spring整个架构是很庞大的,很难一下看完和思考完,所以我会从Core Container进行切入,一步一步往上走,从而解开Spring神秘的底层面纱.同时对Spring的IOC\AOP\

Spring源码解读之BeanFactoryPostProcessor的处理

前言 前段时间旁听了某课堂两节Spring源码解析课,刚好最近自己又在重新学习中,便在这里记录一下学习所得.我之前写过一篇博文,是介绍BeanFactoryPostProcessor跟BeanPostProcessor是如何发挥作用的,当时觉得讲的还行,但是现在看来,太粗劣了,很多地方没涉及到,而且重点都被我忽略了,简直就是蠢得不行.现在就用这篇文章弥补一下前文中对BeanFactoryPostProcessor的讲解,争取把重点讲到,至于BeanPostProcessor,由于涉及到的东西太多

spring源码解读之 JdbcTemplate源码

在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数据库,在JdbcTemplate为用户程序提供了许多便利的数据库操作方法,比如查询,更新等,而且在Spring中,有许多类似 JdbcTemplate的模板,比如HibernateTemplate等等 - 看来这是Rod.Johnson的惯用手法, 所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤. 我们用代码来说

CentOS7最小化源码安装LAMP-步骤详解

系统:CentOS 7.3.1611(最小化安装) 软件:httpd-2.4.27 mysql-5.7.18 php-5.6.3 一.配置系统环境 1.1. 查看系统版本 # cat /etc/centos-release CentOS Linux release 7.3.1611 (Core) 1.2. 查看防火墙状态,关闭防火墙及其开机启动 # systemctl status firewalld # systemctl stop firewalld # systemctl disable

CentOS6系统源码安装LNMP环境详解

一.安装nginx 以下命令均在root权限下执行,普通用户可通过su命令切换1.安装依赖 yum install gcc-c++ yum install pcre pcre-devel yum install openssl openssl-devel 2.下载源码 wget http://nginx.org/download/nginx-1.8.1.tar.gztar -zxvf nginx-1.8.1.tar.gzcd nginx-1.8.1 3.创建nginx用户 useradd -M 

linux下源码编译安装mysql详解

1.redhat5环境下,首先安装编译环境 yum groupinstall -y  "Development Libraries"   "Development Tools" 2.由于源码编译mysql需要cmake命令,所以先要编译安装cmake包 首先下载cmake包,这里下载使用cmake-2.8.8.tar.gz tar xf cmake-2.8.8.tar.gz cd cmake-2.8.8 ./configure make && mak