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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自www.cnblogs.com/sidesky/p/9300322.html
今日推荐