Spring FactoryBean应用

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

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

FactoryBean接口定义

package org.springframework.beans.factory;

public interface FactoryBean {
    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


        
        
        
        
    

org.mybatis.spring.SqlSessionFactoryBean 如下:


package org.mybatis.spring;

public class SqlSessionFactoryBean implements FactoryBean, InitializingBean, ApplicationListener {
private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
        ......
}

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


     
    
    
   
   
        

    
    
     

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

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

}

实践

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

maven依赖:


            com.squareup.okhttp3
            okhttp
            3.6.0

首先,是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:





    
        
        
        
        
        
        
        
    


写个测试类测试一下:

    @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());
    }

你可能感兴趣的:(Spring FactoryBean应用)