做一个合格的程序猿之浅析Spring IoC源码(七)浅谈BeanFactory和FactoryBean

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linuu/article/details/50855446

这一节我们就简单的介绍一下FactoryBean,知道这个接口的作用和意义,方便我们refresh()这个方法的理解

照旧,我们依旧先看源码,从源码中查看一下他的作用吧~

这次就不一句句翻译了(太多了),还是稍微大概的讲一下意思吧:FactoryBean是一个接口,任何一个Bean可以实现这个接口,那么这个bean将成为一个Factory,这个Factory将一些对象暴露出去,这些对象不一定是它们自己,返回的是一个Object对象,这个对象将通过getObject()暴露出去,并且支持单例和prototypes


这个接口有多重要?

看看这段:这个接口在Spring自己的框架中被大篇幅的运用到,举例来说,AOP中link org.springframework.aop.framework.ProxyFactoryBean和org.springframework.jndi.JndiObjectFactoryBean


但是他在非底层代码建设之外并不常见~


扫描二维码关注公众号,回复: 3783055 查看本文章


好了,看了官方的注释,还是有点模糊的吧,不过我们可以再看看ProxyFactoryBean这个官方的代码,其实看名字,“代理”,这个接口可以用于代理,想想也是,“任何bean实现了BeanFactory都可以通过getObject()这个方法去返回一个Object类型的bean,这个就很重要了”


接下来,还是老规矩,我们举个例子,来具体说明这个接口的作用,我们也做一个Proxy,通过切换注入数据库的名字,切换给出的数据库操作,如果我们注入mysql我们就可以操作数据到mysql,如果注入redis我们可以操作数据到redis


首先定义一个数据库操作接口

DBOperation.java

<span style="color:#000000;">package org.study.spring.factorybean;

/**
 * 
 * 数据库操作对象
 */
public interface DBOperation<T extends DBEntity> {
	
	int save(T t);
	
	int update(T t);
	
	int delete(T t);
	
	T select(Integer id);
	

}</span>
DBEntity.java

<span style="color:#000000;">package org.study.spring.factorybean;

/**
 * 
 * 数据库保存对象
 *
 */
public class DBEntity {
	
	private Integer id;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
	

}</span>
MysqlDB.java

<span style="color:#000000;">package org.study.spring.factorybean;

/**
 * mysql数据操作
 * @author
 *
 */
public class MysqlDB implements DBOperation<MysqlDBEntity>{

	public int save(MysqlDBEntity t) {
		System.out.println("save object to mysql");
		return 1;
	}

	public int update(MysqlDBEntity t) {
		System.out.println("update object to mysql");
		return 0;
	}

	public int delete(MysqlDBEntity t) {
		System.out.println("delete object from mysql");
		return 0;
	}

	public MysqlDBEntity select(Integer id) {
		return new MysqlDBEntity();
	}
}</span> 
RedisDB.java

<span style="color:#000000;">package org.study.spring.factorybean;


/**
 * 
 * redis数据库操作
 *
 */
public class RedisDB implements DBOperation<RedisDBEntity>{

	public int save(RedisDBEntity t) {
		System.out.println("save this object"+t.getJsonStr());
		return 1;
	}

	public int update(RedisDBEntity t) {
		System.out.println("update this object"+t.getJsonStr());
		return 0;
	}

	public int delete(RedisDBEntity t) {
		System.out.println("delete this object"+t.getJsonStr());
		return 1;
	}

	public RedisDBEntity select(Integer id) {
		System.out.println("select this object by id "+id);
		return new RedisDBEntity();
	}
	

}</span>
MysqlDBEntity.java

<span style="color:#000000;">package org.study.spring.factorybean;


public class MysqlDBEntity extends DBEntity{
	
	private String attribute;

	public String getAttribute() {
		return attribute;
	}

	public void setAttribute(String attribute) {
		this.attribute = attribute;
	}

}</span>
RedisDBEntity.java

<span style="color:#000000;">package org.study.spring.factorybean;

public class RedisDBEntity extends DBEntity {
	
	private String jsonStr;

	public String getJsonStr() {
		return jsonStr;
	}

	public void setJsonStr(String jsonStr) {
		this.jsonStr = jsonStr;
	}
	

}</span>
ProxyDBObject.java

<span style="color:#000000;">package org.study.spring.factorybean;

import org.springframework.beans.factory.FactoryBean;


/**
 * 
 * DB代理,根据用户注入数据库的名称,自动返回对应的数据库操作给用户
 *
 */
public class ProxyDBObject implements FactoryBean<Object>{
	
	private String currentDB;
	

	public String getCurrentDB() {
		return currentDB;
	}

	public void setCurrentDB(String currentDB) {
		this.currentDB = currentDB;
	}

	public Object getObject() throws Exception {
		if("mysql".equals(currentDB)){
			return new MysqlDB();
		}
		return new RedisDB();
	}

	public Class<?> getObjectType() {
		if("mysql".equals(currentDB)){
			return MysqlDB.class;
		}
		return RedisDB.class;
	}

	public boolean isSingleton() {
		return false;
	}

	 
	 

}</span>

factory-bean.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:context="http://www.springframework.org/schema/context"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
		http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
 
    
          
         <bean id="proxyDB" class="org.study.spring.factorybean.ProxyDBObject">
           <property name="currentDB" value="mysql"/>
         </bean>

</beans>

ProxyDBObjectTest.java

package org.study.spring.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ProxyDBObjectTest{
	
	
	@Test
	public void test2() throws Exception{
		 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("factory-bean.xml");
		 DBOperation dBoperation =  applicationContext.getBean("proxyDB",DBOperation.class);
		 MysqlDBEntity dbEntity = new MysqlDBEntity();
		 dBoperation.save(dbEntity);
	}

}

当配置currentDB为“mysql”时,运行结果是:


切换到redis会报错,因为我们保存的对象是mysqlDBEntity,转换异常


真实开发环境中,可以有2个开发人员,一个写mysql的保存,一个写redis的保存~



举了这么一个例子,其实就只是帮助大家稍微理解一下factoryBean干嘛的,相当于beanfactory.getbean这个返回的bean就是factorybean中getObject中返回的对象


那我们怎么才能够通过beanfactory获取factorybean呢,嘿嘿,其实beanfactory源码中已经有了说明:



通过前缀引用来区分本身和factoryBean,举例说明,如果一个bean叫做myJndiObject,那么getBean("myJndiObject")将获取该bean,如果getBean("&myJndiObject")将获取FactoryBean




修改上面的ProxyDBObjectTest.java

<span style="color:#000000;">package org.study.spring.factorybean;

import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ProxyDBObjectTest{
	
	
	@Test
	public void test2() throws Exception{
		 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("factory-bean.xml");
		 FactoryBean factoryBean =  applicationContext.getBean("&proxyDB",FactoryBean.class);
		 DBOperation db = (DBOperation)factoryBean.getObject();
		 MysqlDBEntity dbEntity = new MysqlDBEntity();
		 db.save(dbEntity);
	}

}</span>
"&"符号可以获取本身,其实吧,BeanFactory和FactoryBean根本没有本质的关联,而且他们都是根接口,没有紧密的关系


关于FactoryBean在Aop中的运用,我们到了AOP再说,我们还是先分析IoC吧~




猜你喜欢

转载自blog.csdn.net/linuu/article/details/50855446