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. 【二十九】php之简易微信二维码支付

    参考二维码支付接口文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 index.php <!DOCTYPE htm ...

  2. cin 与 getchar 中的坑

    今天在一道题上发现一个坑. 输入三个字符,按以下规则求其平均值. (1)如果是数字0~9,那么直接参与求值: (2)如果是其他字符,则其ASCII码参与求值. 输入 输入数据有多组.第一行是数据的组数 ...

  3. leecode第四十三题(字符串相乘)

    class Solution { public: string multiply(string num1, string num2) { ";//特殊情况 ] == ] == ') retu ...

  4. python测试相关小问题

    实操中的小问题 pycharm 一次运行多个test configuration 项目分层,分包之后,tests也分到不同层的不同project里了,tests也分开. 为了防止基层模块改动,影响上层 ...

  5. Codeforces 985 D - Sand Fortress

    D - Sand Fortress 思路: 二分 有以下两种构造, 分别二分取个最小. 代码: #include<bits/stdc++.h> using namespace std; # ...

  6. springboot外置的Servlet容器

    嵌入式Servlet容器:应用打成可执行的jar ​ 优点:简单.便携: ​ 缺点:默认不支持JSP.优化定制比较复杂(使用定制器[ServerProperties.自定义EmbeddedServle ...

  7. 中标麒麟Linux7 如何关闭广播消息

    chmod 600 /usr/libexec/sysnotify pkill -9 sysnotify

  8. 记 linux 下面初次使用的convert 工具完成拼长图功能

    今天,遇到了一个需要把大量图片合并到一个长图的功能.本来找了各种图片处理界顶顶大佬.. “PS(手动一张张 的加).光影魔术手(批处理功能没有看到拼图功能).美图秀秀(可以有个拼图,限制30张,而且需 ...

  9. 【消息队列】从各方面比较下kafka、activemq、rabbitmq、rocketmq之间的区别

    一.单机吞吐量ActiveMQ:万级,吞吐量比RocketMQ和Kafka要低了一个数量级RabbitMQ:万级,吞吐量比RocketMQ和Kafka要低了一个数量级RocketMQ:10万级,Roc ...

  10. 『计算机视觉』FPN:feature pyramid networks for object detection

    对用卷积神经网络进行目标检测方法的一种改进,通过提取多尺度的特征信息进行融合,进而提高目标检测的精度,特别是在小物体检测上的精度.FPN是ResNet或DenseNet等通用特征提取网络的附加组件,可 ...