Spring FactoryBean应用
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应用的更多相关文章
- 转:Spring FactoryBean源码浅析
http://blog.csdn.net/java2000_wl/article/details/7410714 在Spring BeanFactory容器中管理两种bean 1.标准Java Bea ...
- Spring FactoryBean用法
最近在看spring ioc源码,看到FactoryBean这个内容.这个和BeanFactory的区别 1. BeanFactory: 生成bean的工厂,是一个接口,定义了很多方法 2. Fact ...
- Spring FactoryBean 缓存
相关文章 Spring 整体架构 编译Spring5.2.0源码 Spring-资源加载 Spring 容器的初始化 Spring-AliasRegistry Spring 获取单例流程(一) Spr ...
- Spring FactoryBean和BeanFactory 区别
1 BeanFactory 是ioc容器的底层实现接口,是ApplicationContext 顶级接口 spring不允许我们直接操作 BeanFactory bean工厂,所以为我们提供了App ...
- Spring factorybean
自定义FactoryBean 需要实现FactoryBean接口 通过FacotryBean来配置bean的实例. class: 指向FactoryBean的全类名 property:配置Factor ...
- spring FactoryBean配置Bean
概要: 实例代码具体解释: 文件夹结构 Car.java package com.coslay.beans.factorybean; public class Car { private String ...
- Spring学习记录(十)---使用FactoryBean配置Bean
之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...
- Spring之FactoryBean
首先要分辨BeanFactory 与 FactoryBean的区别, 两个名字很像,所以容易搞混 BeanFactory: 以Factory结尾,表示它是一个工厂类,是用于管理Bean的一个工厂 Fa ...
- Spring学习笔记之一----基于XML的Spring IOC配置
1. 在spring配置文件中,如果对一个property进行直接赋值,可使用<value>元素,spring负责将值转化为property指定的类型:也可以直接在property元素上使 ...
随机推荐
- 转youhu科技的文章 勿怪 感激 感激
资源加载 资源加载是加载模块中最为耗时的部分,其CPU开销在Unity引擎中主要体现在Loading.UpdatePreloading和Loading.ReadObject两项中,相信经常查看Prof ...
- 一:requests爬虫基础
一,什么是爬虫? 描述: 本质是一个自动化程序,一个模拟浏览器向某一个服务器发送请求获取响应资源的过程. 爬虫的基本流程 robots.txt协议 编写一个robots.txt的协议文件来约束爬虫程序 ...
- 设置本地虚拟域名windows+apache
C:\WINDOWS\system32\drivers\etc\hosts 在这个文件中 最下面添加. 127.0.0.1 localhost.com 127.0.0.1 cho.com 12 ...
- HAProxy用法详解
一.HAProxy简介 (1)HAProxy 是一款提供高可用性.负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费.快速并且可靠的一种解决方案. HAProx ...
- python中那些双下划线开头得函数和变量
Python中下划线---完全解读 Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用’from module import *’导入 __xxx__ 系统定义名字 __x ...
- Gradle实现编译差异
今天开发组长问了这么一个问题,如何实现通过gradle编译动态设置代码里的一些值.可能这么说不太明白,下面说依稀具体需求. 开发中有两个服务器:一个用于测试版本.一个用于线上版本发布,这两个服务器地址 ...
- 第 6 章 存储 - 044 - volume 生命周期管理
volume 生命周期管理 1)备份 因为 volume 实际上是 host 文件系统中的目录和文件,所以 volume 的备份实际上是对文件系统的备份 例如:本地的Registry,所有镜像都存在/ ...
- nodejs中function*、yield和Promise的示例
var co = require("co"); var fs = require("fs"); function cusReadFile(fileName) { ...
- office2016如何激活
office2016如何激活 一.总结 一句话总结:office2016没有激活成功,下了一个office2013破解版 office2013破解版 二.自己做法 三中的方法点赞蛮多的(100多个), ...
- LeetCode--268--缺失数字
问题描述: 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数. 示例 1: 输入: [3,0,1] 输出: 2 示例 2: 输入: [9 ...