这一节我们就简单的介绍一下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>
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吧~