这一节我们就简单的介绍一下FactoryBean,知道这个接口的作用和意义,方便我们refresh()这个方法的理解
照旧,我们依旧先看源码,从源码中查看一下他的作用吧~
这次就不一句句翻译了(太多了),还是稍微大概的讲一下意思吧:FactoryBean是一个接口,任何一个Bean可以实现这个接口,那么这个bean将成为一个Factory,这个Factory将一些对象暴露出去,这些对象不一定是它们自己,返回的是一个Object对象,这个对象将通过getObject()暴露出去,并且支持单例和prototypes
这个接口有多重要?
看看这段:这个接口在Spring自己的框架中被大篇幅的运用到,举例来说,AOP中link org.springframework.aop.framework.ProxyFactoryBean和org.springframework.jndi.JndiObjectFactoryBean
但是他在非底层代码建设之外并不常见~
好了,看了官方的注释,还是有点模糊的吧,不过我们可以再看看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>
<?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>
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); } }
切换到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吧~