• 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());
        }
    
  • 相关阅读:
    springboot调优
    韩立刚计算机网络笔记-第08章 传输层
    韩立刚计算机网络笔记-第07章 网络层协议
    韩立刚计算机网络笔记-第06章 动态路由和静态路由
    韩立刚计算机网络笔记-第05章 IP地址和子网划分
    韩立刚计算机网络笔记-第04章 数据链路层
    韩立刚计算机网络笔记-第03章 GNS网络模拟器
    韩立刚计算机网络笔记-第02章 物理层
    韩立刚计算机网络笔记-第01章 计算机网络详解
    算法很美 笔记 12.图结构
  • 原文地址:https://www.cnblogs.com/tiancai/p/9604426.html
Copyright © 2020-2023  润新知