看清楚是FactoryBean,不是BeanFactory,虽然他们长得很像,但作用确实天差地别,BeanFactory是bean工厂,前面的博客已经介绍过了,他们工厂类的基础接口,而FactoryBean是一种bean,那为什么要有这种bean呢,和一般的bean有什么区别呢?下面跟大家分享一下FactoryBean。
一、为什么需要FactoryBean
我们知道spring里一切皆是bean,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,但是有些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。这时FactoryBean就出现了,FactoryBean就是通过编码的方式灵活的创建bean的实例,这也是工厂模式设计模式的运用。
二、什么是FactoryBean
FactoryBean是一个接口,get 就是创建bean实例的关键方法。
public interface FactoryBean {
/**
* Return an instance (possibly shared or independent) of the
* managed by this factory. As with a BeanFactory, this allows
* support for both the Singleton and Prototype design pattern.
* @return an instance of the bean (should never be null)
* @throws Exception in case of creation errors
*/
get () throws Exception;
/**
* Return the type of that this FactoryBean creates, or null
* if not known in advance. This allows to check for specific types of
* beans without instantiating s, e.g. on autowiring.
* <p>For a singleton, this can simply return get ().getClass(),
* or even null, as autowiring will always check the actual s
* for singletons. For prototypes, returning a meaningful type here
* is highly advisable, as autowiring will simply ignore them else.
* @return the type of that this FactoryBean creates, or null
* @see ListableBeanFactory#getBeansOfType
*/
Class get Type();
/**
* Is the bean managed by this factory a singleton or a prototype?
* That is, will get () always return the same ?
* <p>The singleton status of the FactoryBean itself will
* generally be provided by the owning BeanFactory.
* @return if this bean is a singleton
*/
boolean isSingleton();
}
get ():返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。
boolean isSingleton():返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
Class<T> get Type():返回FactoryBean创建的bean类型。
bean工厂创建bean对象时要判断改对象是否是FactoryBean,如果是FactoryBean则调用他的get ()方法获取实例化bean。AbstractBeanFactory源码如下:
protected get ForSharedInstance(String name, beanInstance) {
String beanName = transformedBeanName(name);
// Don\'t let calling code try to dereference the
// bean factory if the bean isn\'t a factory
if (isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance);
}
// Now we have the bean instance, which may be a normal bean
// or a FactoryBean. If it\'s a FactoryBean, we use it to
// create a bean instance, unless the caller actually wants
// a reference to the factory.
if (beanInstance instanceof FactoryBean) {
if (!isFactoryDereference(name)) {
// return bean instance from factory
FactoryBean factory = (FactoryBean) beanInstance;
logger.debug(\"Bean with name \'\" + beanName + \"\' is a factory bean\");
try {
beanInstance = factory.get ();
}
catch (BeansException ex) {
throw ex;
}
catch (Exception ex) {
throw new BeanCreationException(\"FactoryBean threw exception on creation\", ex);
}
if (beanInstance == null) {
throw new FactoryBeanCircularReferenceException(
\"Factory bean \'\" + beanName + \"\' returned null - \" +
\"possible cause: not fully initialized due to circular bean reference\");
}
}
else {
// the user wants the factory itself
logger.debug(\"Calling code asked for FactoryBean instance for name \'\" + beanName + \"\'\");
}
}
return beanInstance;
}
三、demo
(转自:https://www.jianshu.com/p/6f0a59623090)
当前微服务日趋流行,项目开发中不可避免的需要去调用一些其他系统接口,这个时候选择一个合适的HTTP client library 就很关键了,本人项目开发中使用 Square 开源的OkHttp 。
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.spring work.beans.factory.DisposableBean;
import org.spring work.beans.factory.FactoryBean;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
/**
* ${DE ION}
*
* @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 get () 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<?> get Type() {
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. :
<? version=\"1.0\" encoding=\"UTF-8\"?>
<beans ns=\"http://www.spring work.org/schema/beans\" ns:xsi=\"http://www.w3.org/2001/ Schema-instance\"
ns:context=\"http://www.spring work.org/schema/context\"
ns:util=\"http://www.spring work.org/schema/util\"
xsi:schemaLocation=\"
http://www.spring work.org/schema/beans http://www.spring work.org/schema/beans/spring-beans.xsd
http://www.spring work.org/schema/util http://www.spring work.org/schema/util/spring-util.xsd
http://www.spring work.org/schema/context http://www.spring work.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());
}
继续阅读与本文标签相同的文章
MXC抹茶基金宣布战略投资区块链内容社区芥末圈
-
3步轻松搞定Spring Boot缓存
2026-05-18栏目: 教程
-
5G机皇已来 三星Galaxy Note10+5G正式登陆中国
2026-05-18栏目: 教程
-
威特动力:从“制造”到“智造”的跨越
2026-05-18栏目: 教程
-
Nreal携手运营商KDDI,共推日本MR生态建设
2026-05-18栏目: 教程
-
智能安防系统不可不知安全策略有哪些?
2026-05-18栏目: 教程
