文档章节

Spring FactoryBean 详解

OrangeJoke
 OrangeJoke
发布于 2017/11/26 10:27
字数 718
阅读 330
收藏 15

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

引言

在 mybatis-spring 中,我们会使用 MapperFactoryBean 为我们 的mapper(interface)创建代理类。 SqlSessionFactoryBean 通过dataSource成属性创建对应的sqlSessionFactory。两个接口都实现了Spring FactoryBean interface。所以我们就通过这个来理解一下 Spring FactoryBean.

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

FactoryBean

Customizing instantiation logic with a FactoryBean,Implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.

简介:
first,FactoryBean 是一个扩展点,主要是扩展创建复杂的对象实现。
second, 实现了FactoryBean接口的类自己就是一个factory,可以创建对象。接口一共三个方法,我们重点看一下其中的 getObject();

Object getObject(): returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.

boolean isSingleton(): returns true if this FactoryBean returns singletons, false otherwise.

Class getObjectType(): returns the object type returned by the getObject() method or null if the type is not known in advance.

对照这个过程我们就阅读一下mybatis-spring MapperFactoryBean的源码,这里不再重复,请参考 http://blog.csdn.net/tanqidong1992/article/details/48026491

这里说明一下: sessionSqlTemplate 实现SqlSession, sessionSqlTemplates是线程安全的,所以在FactoryBean getObject的时候就注入了SqlSession,所以完成之后,mapper可以直接使用。

如果不看具体的代理对象生成过程,我们就可以理解了整个对象的创建过程,比如SqlSessionFactoryBean就使用了一个build方法。

FactoryBean 的好处就是简化复杂对象的创建,上面的创建过程绑定了sqlSession,通过代理生成了代理对象,这样使用起来就非常简单了。

Interface 生成代理对象

现在我们来看下为mapper接口生成代理对象的过程:

public class MapperRegistry {

  private Configuration config;
// 为每个mapper类型存储一个对应的MapperProxyFactory
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null)
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    try {
        //我们直接看这部分代码吧
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
...
}

MapperProxyFactory

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

MapperProxy

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

}

参考: https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/

© 著作权归作者所有

OrangeJoke
粉丝 40
博文 57
码字总数 39185
作品 0
江北
高级程序员
私信 提问
Spring BeanFactory和FactoryBean

Spring BeanFactory和FactoryBean 1、BeanFactory BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是 Spring IOC所遵守的最底层和最基本的编程规范...

秋风醉了
2018/04/16
94
0
Spring的FactoryBean

首先我们要知道Spring就是一个大的Bean容器池,用户通过简单的配置,让Spring帮忙实例化对象,而Spring是通过反射原理创建Bean的。 然后我们知道一般情况下我们配置Bean时使用的是类的全路径...

sunranhou
03/15
17
0
Spring拓展接口之FactoryBean,我们来看看其源码实现

是什么 FactoryBean的源码比较简单,大家可以细读下其注释,我做了简单的如下翻译 /** 实现此接口的bean不能用作普通bean。此bean暴露的对象是通过getObject()创建的对象,而不是它自身 */pu...

java菜分享
03/25
10
0
Spring IOC FactoryBean检测与获取Bean

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。Spring FactoryBean是创建复杂的bean,一般的bean直接用xml配置即可,如果一个bean的创建过程中涉及到很多其他的b...

哲别0
2018/05/28
94
0
说说 Spring 框架中的 Factory Bean

一般情况下, Spring 通过反射机制利用 的 class 属性指定实现类来实例化 bean。 但在某些情况下,实例化 bean 的过程比较复杂,如果按照传统的方式,则需要在 中提供大量的配置信息,这时如...

deniro
2018/05/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

写的简单sh脚本2

#!/bin/bashexport LANG="en_US.UTF-8"#chmod +x filename 记得给文件加可执行权限#./vsimstart.sh#启动vsim项目echo "start vism"#207------------------------------assets=vsim-a......

hexiaoming123
昨天
4
0
java基础(1)变量和常量

概要和总结: 数据类型图: 基本数据类型:只有基本功能-----保存数据 (4类8种)byte-short-int-long-float-double-char-boolean 引用数据类型:有更多功能,保存数据,处理数据...

煌sir
昨天
5
0
年底了,整理了一份程序员面试必看的文章合集

本系列文章整合了本号发表和转载过的,有关技术招聘干货、笔试面试经验和技巧、简历、招聘等方面的精品文章,希望对想要找工作,以及正在找工作的你,能够有所帮助。 原创面试干货文章 校招季...

Java技术江湖
昨天
4
0
curl 命令行下工作的文件传输工具---应用篇

抓取页面内容到一个文件中 curl -o home.html http://www.sina.com.cn 模拟用户登录 # 此参数相当于设置http头 Authorization:curl --user user:password http://blog.mydomain.com/logi...

edison_kwok
昨天
4
0
JAVA--高级基础开发Cookie实现记住用户名和密码

前端JSP页面: 实现保存用户名和密码<%@ page import="java.net.URLDecoder" %><%@ page contentType="text/html;charset=UTF-8" language="java" %><html> <head> <title>Coo......

李文杰-yaya
昨天
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部