文档章节

Spring核心——FactoryBean

随风溜达的向日葵
 随风溜达的向日葵
发布于 07/12 14:00
字数 1157
阅读 1557
收藏 22

本文继续之前的2篇文章(BeanPostProcessorBeanFactoryPostProcessor)介绍Ioc容器的功能扩展。

FactoryBean是用来构造Bean的接口。常规情况下向容器添加一个Bean只需要像下面这样通过XML的配置或注解直接引入这个类即可:

<bean id="a" class="x.y.z.A">
     <property name="setter" value="1" />
</bean>
@Component
class A{}

但是某些情况下我们需要动态的装载一个复的Bean,此时可以使用FactoryBean来动态装载一个Bean。FactoryBean字面上看就知道它是一个Bean,但是有Factory的功能(工厂模式)。

FactoryBean的使用和之前介绍的Processor 一样,实现一个接口,然后设置为一个Spring的Bean即可:

class MyFactory implements FactoryBean{
	@Override
	public Object getObject() throws Exception {
		return null;
	}

	@Override
	public Class getObjectType() {
		return null;
	}
}

下面通过一个适配器的例子来说明FactoryBean的使用,文中的代码仅用于示例,可执行源码请移步 https://gitee.com/chkui-com/spring-core-sample 中的 chkui.springcore.example.xml.factorybean包。

例子是使用适配器模式对对应的资源进行解码,执行一下3步:

  1.  容器启动之后会加载一个密文资源类,可能是Base64的编码,也可能是UrlBase64的编码,根据配置来确定。
  2.  FactoryBean会根据资源类型向容器添加一个解码的适配器。
  3.  最后用适配器解码输出。

例子的代码结构如下:

factorybean
--BeanFactoryApp.java main方法
--AdapterFactory.java 一个FactoryBean,用于生成适配器Bean
--entity
----Text.java 编码资源类的接口
----Base64Entity.java Base64编码
----UrlBase64Entity.java urlBase64编码
--adapter
----DecodeAdapter.java 解码适配器接口
----Base64Adapter.java Base64的解码适配器 
----UrlBase64Adapter.java UrlBase64的解码适配器 

另外配置文件在 resources/xml/factorybean/config.xml:

<beans>
    <!-- Base64编码 -->
    <bean class="chkui.springcore.example.xml.factorybean.entity.Base64Entity">
     	<constructor-arg value="一串加密的文字。URLBase64和Base64的区别是调整了可以用于URL的符号,例如+替换为-。"/>
    </bean>
    <!-- UrlBase64编码 -->
    <!-- <bean class="chkui.springcore.example.xml.factorybean.entity.UrlBase64Entity">
     	<constructor-arg value="一串加密的文字。URLBase64和Base64的区别是调整了可以用于URL的符号,例如+替换为-。"/>
    </bean> -->
    <bean id="adapter" class="chkui.springcore.example.xml.factorybean.AdapterFactory" />
</beans>

Base64Entity和UrlBase64Entity是2个资源类,分别用Base64和UrlBase64对字符串进行编码,通过配置来管理。下面是Text和Base64Entity的代码:

package chkui.springcore.example.xml.factorybean.entity;

//文本资源接口
public interface Text {
	//定义资源类型,目前支持Base64和UrlBase642种加密编码文件
	public static enum Type{
		Base64,
		UrlBase64
	}
	//获取资源编码类型
	Type getType();
	//获取编码的密文
	String getCipher();
}
package chkui.springcore.example.xml.factorybean.entity;

public class Base64Entity implements Text {
	private String cipher;

	public Base64Entity(String text) {
		this.cipher = Base64.getEncoder().encodeToString(text.getBytes());
	}
	
	@Override
	public Type getType() {
		return Text.Type.Base64;
	}

	@Override
	public String getCipher() {
		return cipher;
	}
}

然后我们根据不同的资源定义了不同的适配器来解码,下面是适配器接口和一个实现类——DecodeAdapter、Base64Adapter:

package chkui.springcore.example.xml.factorybean.adapter;

//加密编码文件解码适配器
public interface DecodeAdapter {
	//获取解码之后的明文
	String getPlain();
}
package chkui.springcore.example.xml.factorybean.adapter;

public class Base64Adapter implements DecodeAdapter {
	private String cipher;

	public Base64Adapter(String cipher){
		this.cipher = cipher;
	}
	
	@Override
	public String getPlain() {
		return new String(Base64.getDecoder().decode(cipher));
	}
}

最后是核心的FactoryBean——AdapterFactory,他的作用是根据当前向IoC添加的资源类型来确定启用哪个适配器。AdapterFactory继承了BeanFactoryAware以便获得BeanFactory实例:

public class AdapterFactory implements FactoryBean<DecodeAdapter>, BeanFactoryAware {
	private Text text;
	private volatile DecodeAdapter adapter;

	@Override
	public DecodeAdapter getObject() throws Exception {
		//根据IoC中的资源类型选择适配器,懒加载模式
		return lazyLoadAdapter();
	}

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

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.text = beanFactory.getBean(Text.class);
	}

	private DecodeAdapter lazyLoadAdapter() {
		if (null == adapter) {
			synchronized (AdapterFactory.class) {
				if (null == adapter) {
					switch (text.getType()) {
					case UrlBase64: 
						adapter = new UrlBase64Adapter(text.getCipher());
						break;
					case Base64:
					default:
						adapter = new Base64Adapter(text.getCipher());
						break;
					}
				}
			}
		}
		return this.adapter;
	}
}

lazyLoadAdapter方法实现了适配的过程——根据不同的编码类型返回不同的适配器。最后运行容器:

package chkui.springcore.example.xml.factorybean;
public class BeanFactoryApp {
    public static void main(String[] args) {
    	ApplicationContext context = new ClassPathXmlApplicationContext("xml/factorybean/config.xml");
    	Text text = context.getBean(Text.class);
		System.out.println("密文:" + text.getCipher());
		System.out.println("编码类型:" + text.getType());
		DecodeAdapter decode = context.getBean(DecodeAdapter.class);
		System.out.println("明文:" + decode.getPlain());
    }
    //通过符号规则获取工厂Bean
    private static void nameSymbol(ApplicationContext context) {
    	Object adapter = context.getBean("adapter");//获取实际Bean
		System.out.println("adapterClass :" + adapter.getClass().getName());
		adapter = context.getBean("&adapter");//获取实际工厂Bean
		System.out.println("adapterClass :" + adapter.getClass().getName());
    }
}

实际上,Spring的所有预设Bean都是通过FactoryBean实现的,现在大概有50多个Spring官方实现的FactoryBean。

注意nameSymbol方法中的代码和BeanFactory的配置——<bean id="adapter" class="chkui.springcore.example.xml.factorybean.AdapterFactory" />。如果为BeanFactory指定了ID或别名,那么通过ID获取到的是工厂生成Bean而不是这个工厂本身。但是可以通过在之前增加"&"符号来告诉IoC获取BeanFactory本身。

 

© 著作权归作者所有

共有 人打赏支持
随风溜达的向日葵
粉丝 275
博文 77
码字总数 166662
作品 0
广州
其他
私信 提问
加载中

评论(3)

Java烂猪皮
Java烂猪皮

引用来自“OSC_烂猪皮”的评论

文章写得不错,能否给予转载?
好的
随风溜达的向日葵
随风溜达的向日葵

引用来自“OSC_烂猪皮”的评论

文章写得不错,能否给予转载?
没问题。请注明作者和出处,谢谢。
Java烂猪皮
Java烂猪皮
文章写得不错,能否给予转载?
Spring框架笔记(十一)——IOC容器创建bean实例的第三种方法——FactoryBean

IOC容器创建bean实例有3类方法: 1 通过bean对应实例的全类名 2 通过工厂方法,包括静态工厂和实例工厂 3 实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean 今天我们介绍这第三种方法——...

HappyBKs
2015/07/21
0
0
Spring BeanFactory和FactoryBean的区别

有些东西可能知其用,但也需知其所以然,特转载该篇Spring BeanFactory和FactoryBean的区别 及 包是 Spring IoC 容器的基础。 一、BeanFactory 定义了IOC容器的最基本形式,并提供了IOC容器应...

淡淡的倔强
09/07
0
0
Quartz与Spring的整合使用——创建JobDetail的方式及Trigger

之前说到过Quartz的基本使用(猛戳这里看文章),在实际使用中,我们通常会将定时任务交由spring容器来管理,所以今天我们来说说Quartz与spring的整合。 咱们还是按照Quartz的三大元素的顺序...

哲别0
2017/10/25
0
0
【死磕 Spring】—– IOC 之从单例缓存中获取单例 bean

原文出自:http://cmsblogs.com 从这篇博客开始我们开始加载 bean 的第一个步骤,从缓存中获取 bean,代码片段如下: 首先调用 从缓存中获取 bean,在上篇博客 【死磕 Spring】----- 加载 be...

chenssy
10/18
0
0
【死磕 Spring】—– IOC 之分析各 scope 的 bean 创建

原文出自:http://cmsblogs.com 在 Spring 中存在着不同的 scope,默认是 singleton ,还有 prototype、request 等等其他的 scope,他们的初始化步骤是怎样的呢?这个答案在这篇博客中给出。...

chenssy
10/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【Flutter教程】从零构建电商应用(一)

在这个系列中,我们将学习如何使用google的移动开发框架flutter创建一个电商应用。本文是flutter框架系列教程的第一部分,将学习如何安装Flutter开发环境并创建第一个Flutter应用,并学习Flu...

笔阁
27分钟前
5
0
什么是以太坊DAO?(三)

Decentralized Autonomous Organization,简称DAO,以太坊中重要的概念。一般翻译为去中心化的自治组织。 投票支付合约的所有费用和行动需要时间,并要求用户始终保持活跃,知情和专注。另一...

geek12345
29分钟前
2
0
一个本科学生对Linux的认知

一个本科学生对Linux的认知 我是一名大三的普通一本大学的软件工程的一名学生,学校开设了一些关于系统开发的课程,纸上得来终觉浅,学校的课程课时较短,想要在56个课时之内学会一些公司需要...

linuxCool
今天
3
0
CentOS 安装Tomcat

Tomcat 介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 Java 程序写的网站用tomcat+jdk来运...

野雪球
今天
1
0
OSChina 周四乱弹 —— 每天都迟到是种什么样的体验

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @开源中国首席机器人 :《Too Good At Goodbyes (Acoustic) - Sam Smith - 单曲》 《Too Good At Goodbyes (Acoustic) - Sam Smith - 单曲》 ...

小小编辑
今天
1K
14

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部