Spring 中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean 即 FactoryBean。FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。

本文简单分析工厂FactoryBean的用法。

FactoryBean接口定义

package org.springframework.beans.factory;

public interface FactoryBean<T> {
T getObject() throws Exception; Class<?> getObjectType(); boolean isSingleton();
}

应用场景

FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。

应用案例

很多开源项目在集成Spring 时都使用到FactoryBean,比如 MyBatis3 提供 mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean

<bean id="tradeSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="trade" />
<property name="mapperLocations" value="classpath*:mapper/trade/*Mapper.xml" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="typeAliasesPackage" value="com.bytebeats.mybatis3.domain.trade" />
</bean>

org.mybatis.spring.SqlSessionFactoryBean 如下:


package org.mybatis.spring; public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
......
}

另外,阿里开源的分布式服务框架 Dubbo 中的Consumer 也使用到了FactoryBean:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
"> <!-- 当前应用信息配置 -->
<dubbo:application name="demo-consumer" /> <!-- 暴露服务协议配置 -->
<dubbo:protocol name="dubbo" port="20813" /> <!-- 暴露服务配置 -->
<dubbo:reference id="demoService" interface="com.alibaba.dubbo.config.spring.api.DemoService" /> </beans>

<dubbo:reference 对应的Bean是com.alibaba.dubbo.config.spring.ReferenceBean 类,如下:

public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {

}

实践

当前微服务日趋流行,项目开发中不可避免的需要去调用一些其他系统接口,这个时候选择一个合适的HTTP client library 就很关键了,本人项目开发中使用 Square 开源的OkHttp ,关于OkHttp 可以参考 OkHttp Recipes
OkHttp本身的API 已经非常好用了,结合Spring 以及在其他项目中复用的目的,对OkHttp 创建过程做了一些封装,例如超时时间、连接池大小、http代理等。

maven依赖:

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.6.0</version>
</dependency>

首先,是OkHttpClientFactoryBean ,代码如下:

package com.bytebeats.codelab.http.okhttp;

import com.bytebeats.codelab.http.util.StringUtils;
import okhttp3.*;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean; import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit; /**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2017-03-04 22:18
*/
public class OkHttpClientFactoryBean implements FactoryBean, DisposableBean {
private int connectTimeout;
private int readTimeout;
private int writeTimeout; /**http proxy config**/
private String host;
private int port;
private String username;
private String password; /**OkHttpClient instance**/
private OkHttpClient client; @Override
public Object getObject() throws Exception { ConnectionPool pool = new ConnectionPool(5, 10, TimeUnit.SECONDS); OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.connectionPool(pool); if(StringUtils.isNotBlank(host) && port>0){
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(host, port));
builder.proxy(proxy);
} if(StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)){
Authenticator proxyAuthenticator = new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
};
builder.proxyAuthenticator(proxyAuthenticator);
} client = builder.build();
return client;
} @Override
public Class<?> getObjectType() {
return OkHttpClient.class;
} @Override
public boolean isSingleton() {
return true;
} @Override
public void destroy() throws Exception {
if(client!=null){
client.connectionPool().evictAll();
client.dispatcher().executorService().shutdown();
client.cache().close();
client = null;
}
} public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
} public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
} public void setWriteTimeout(int writeTimeout) {
this.writeTimeout = writeTimeout;
} public void setHost(String host) {
this.host = host;
} public void setPort(int port) {
this.port = port;
} public void setUsername(String username) {
this.username = username;
} public void setPassword(String password) {
this.password = password;
} }

项目中引用 applicationContext.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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="okHttpClient" class="com.bytebeats.codelab.http.okhttp.OkHttpClientFactoryBean">
<property name="connectTimeout" value="2000" />
<property name="readTimeout" value="2000" />
<property name="writeTimeout" value="2000" />
<property name="host" value="" />
<property name="port" value="0" />
<property name="username" value="" />
<property name="password" value="" />
</bean> </beans>

写个测试类测试一下:

    @Resource
private OkHttpClient client; public void run() throws Exception {
Request request = new Request.Builder()
.url("https://www.baidu.com/")
.build(); Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string());
}

作者:FX_SKY
链接:https://www.jianshu.com/p/6f0a59623090
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Spring FactoryBean应用的更多相关文章

  1. 转:Spring FactoryBean源码浅析

    http://blog.csdn.net/java2000_wl/article/details/7410714 在Spring BeanFactory容器中管理两种bean 1.标准Java Bea ...

  2. Spring FactoryBean用法

    最近在看spring ioc源码,看到FactoryBean这个内容.这个和BeanFactory的区别 1. BeanFactory: 生成bean的工厂,是一个接口,定义了很多方法 2. Fact ...

  3. Spring FactoryBean 缓存

    相关文章 Spring 整体架构 编译Spring5.2.0源码 Spring-资源加载 Spring 容器的初始化 Spring-AliasRegistry Spring 获取单例流程(一) Spr ...

  4. Spring FactoryBean和BeanFactory 区别

    1 BeanFactory 是ioc容器的底层实现接口,是ApplicationContext 顶级接口 spring不允许我们直接操作 BeanFactory  bean工厂,所以为我们提供了App ...

  5. Spring factorybean

    自定义FactoryBean 需要实现FactoryBean接口 通过FacotryBean来配置bean的实例. class: 指向FactoryBean的全类名 property:配置Factor ...

  6. spring FactoryBean配置Bean

    概要: 实例代码具体解释: 文件夹结构 Car.java package com.coslay.beans.factorybean; public class Car { private String ...

  7. Spring学习记录(十)---使用FactoryBean配置Bean

    之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...

  8. Spring之FactoryBean

    首先要分辨BeanFactory 与 FactoryBean的区别, 两个名字很像,所以容易搞混 BeanFactory: 以Factory结尾,表示它是一个工厂类,是用于管理Bean的一个工厂 Fa ...

  9. Spring学习笔记之一----基于XML的Spring IOC配置

    1. 在spring配置文件中,如果对一个property进行直接赋值,可使用<value>元素,spring负责将值转化为property指定的类型:也可以直接在property元素上使 ...

随机推荐

  1. NOI2017 游记

    成功在NOI2017退役……现在的我已经是一只退役狗了 结果也一直到了退役,我都还不会半平面交,不会单纯形,不会非旋转版Treap…… FWT我也不熟,分治FFT我也只写过一道板子题 但是现在已经退役 ...

  2. go 单进程并发

    demo1 // This sample program demonstrates how to create goroutines and // how the scheduler behaves. ...

  3. C++.可变参数_ZC测试

    ZC:环境: Win7 x64(旗舰版),Microsoft Visual Studio 2010(版本 10.0.30319.1 RTMRel, Microsoft .NET Framework(版 ...

  4. PostgreSQL安装及使用教程一(exe安装方式)

    下载安装 百度搜索PostgreSQL,进入官网,选择相应版本的图形化安装程序(BigSQL)安装即可 连接数据库 对数据库操作有两种方式,一种是通过命令行工具psql,另一种是通过图形化界面pgAd ...

  5. DAY5 基本数据类型及内置方法

    一.可变与不可变数据类型 1.可变类型:值改变,但是id不变,证明就是在改变原值,是可变类型 2.不可变类型:值改变,但是id也跟着变,证明是产生了新的值,是不可变类型 二.数字类型 1.整型int ...

  6. MySQL学习(九)

    1 一道面试题 新建两张表 mysql> create table m -> ( -> mid int, -> hid int, -> gid int, -> mr ...

  7. MATLAB程序控制结构

  8. jquery如何获取checkbox的值

    jquery如何获取checkbox的值 一.总结 一句话总结:就是通过jquery获取哪些对应name的checkbox,然后找出:check(被选中的),然后通过jquery的each遍历获取这些 ...

  9. Win7无法保存共享帐户密码

    每次机器重启完之后,网络共享的密码总是要重新输入. [记住我的凭据]选项不起作用. 查到了下面百度经验的文章,挺靠谱的. https://jingyan.baidu.com/article/59a01 ...

  10. ubuntu 14.04 postgresql 的总结

    1)为了允许远程连接: a) http://askubuntu.com/questions/423165/remotely-access-postgresql-database To open the ...