相信在开发中,尤其是mybatis 配置操作中,我们只需要提供一个mapper 接口,然后注入到service 中,就可以进行调用。

按我们的一般逻辑来说,我们并没有进行接口的实现,应该会报空指针异常,那么Mybatis 是如何进行操作的呢?

这主要是得于Spring 强大的扩展机制,进入正题:

1. Spring 提供了 BeanDefinitionRegistryPostProcessor 接口,通过这个接口的实现,可以自定义一些我们bean ,让Spring 在初始化的时候进行bean 的加载

implements BeanDefinitionRegistryPostProcessor

2.Spring 提供了  FactoryBean的接口,源码中解释说:如果一个bean 实现了这个接口,它将会作为一个工厂对象暴露出来,而不是直接的作为一个bean 的实例

暴露出来;反而它是用来创建bean的实例的,

意思就是;在我们的bean 对象被spring管理后,spring在获取bean 对象时候底层调用的是getBean()方法,默认下getBean 返回的是该类的无参数构造,这一点毋庸置疑,当然还有一种就是对于实现了FactoryBean 接口的类,在spring调用 getBean()方法时候,调用的是FactoryBean 下的 getObject方法进行对象的引用创建,所以利用特性,可以进行生成接口的代理;dubbo也是如此(只不过是通过自定义标签的方式实现的)

implements FactoryBean

实例代码如下:

/**
* 实现FactoryBean 的bean,将会被作为一个对象的工厂,
* 不会直接的作为bean 的实例暴露在外边,而是通过getObject 方法
* 进行对象的引用,也就是说这个对象的实例是通过getObject 方法返回的
* @author iscys
*
*/
public class BeanFactoryDoc implements FactoryBean { public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:springTest/my.xml"); Object bean = app.getBean("beanFactory");
//返回的是1 ,并没有返回BeanFactoryDoc 的对象实例;
System.out.println(bean);
} @Override
public Object getObject() throws Exception {
//实际返回的对象
return "1";
} @Override
public Class getObjectType() {
//返回的对象类型
return "1".getClass();
} @Override
public boolean isSingleton() {
return true;
} }

------>. 结果返回的是  1 ;而不是 BeanFactoryDoc对象,

将第一点与第二点结合起来再加上jdk动态代理,我们就可以进行动态生成接口代理对象,并且可以进行注入的操作;

接下来我进行模拟接口动态代理的生成:(BeanDefinitionRegistryPostProcessor  + FactoryBean + jdk proxy)

(一).随便来个接口:

interface TestInterface{

    void testMethod();
}

(二).实现  BeanDefinitionRegistryPostProcessor 接口主要是  postProcessBeanDefinitionRegistry, 可以使用 registry实现将自定义bean 注册到Spring中;

/**
* spring 通过暴露BeanDefinitionRegistryPostProcessor 接口,
* 可以使我们在spring中加载一些我们自定义的bean,被spring 所初始化;例如
* mybatis 接口代理对象就是通过这种方式加载进来的
* 接下来模拟接口代理的生成方法
* 1.知识补充,都知道,在我们的bean 对象被spring管理后,spring在获取bean 对象时候调用的是getBean()方法
* 默认下getBean 返回的是该类的无参数构造,当然还有一种就是对于实现了FactoryBean 接口的类,在spring调用
* getBean()方法时候,调用的是FactoryBean 下的 getObject方法所返回的对象,所以利用特性,可以进行生成接口的
* 代理;dubbo也是如此
*
* @author iscys
*
*/
public class BeanDefinitionRegistryDoc implements BeanDefinitionRegistryPostProcessor { public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:springTest/my.xml"); Object bean = app.getBean("testInterface");
System.out.println(bean);
System.out.println(bean instanceof TestInterface );
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub } /**
* 通过这个方法将我们自定义的bean 进行加载进来
*/
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//bean的定义,这些都是常规的配置
GenericBeanDefinition beanDefinition =new GenericBeanDefinition();
//设置bean class对象交给BeanFactory 进行创建,会根据beanclass进行对象的初始化
beanDefinition.setBeanClass(BeanFactory.class);
//对象初始化赋值操作,给bean 的变量属性的赋值,要有属性的set方法才可以成功的赋值,底层是ArrayList
beanDefinition.getPropertyValues().addPropertyValue("needProxyInterface", "com.baseknow.spring.TestInterface");
//注册到bean工厂中将bean,这一步完成后Spring就可以初始化bean 对象了;
registry.registerBeanDefinition("testInterface", beanDefinition);
} }

(三),要我来说,实现 FactoryBean 这个才是真正的核心哈哈,因为可以通过 getObject() 进行自定义对象的生成

/**
* 实现FactoryBean bean工厂
* 不会直接的作为bean 的实例暴露在外边,而是通过getObject 方法
* 进行对象的引用,也就是说这个对象的实例是通过getObject 方法返回的
* @author cys
*
*/
class BeanFactory implements FactoryBean{ //接口属性
private Class needProxyInterface; public Class getNeedProxyInterface() {
return needProxyInterface;
}
  //生成set方法
public void setNeedProxyInterface(Class needProxyInterface) {
this.needProxyInterface = needProxyInterface;
} @Override
public Object getObject() throws Exception {
System.out.println("---------getObject");
//jdk代理,进行代理,获取代理对象,将接口传入
return getProxy().newProxy(needProxyInterface);
} @Override
public Class getObjectType() {
return this.needProxyInterface;
} @Override
public boolean isSingleton() {
return true;
} InterfaceProxy getProxy(){
return new JdkProxy();
}
}

(四).jdk 动态代理

/**
* JDK 动态代理模版通用方法,接口代理
* 具体功能再进行增加
* @author iscys
*
*/
public class JdkProxy implements InvocationHandler ,Serializable { private static final long serialVersionUID = -4467164789570764661L; @SuppressWarnings("unchecked")
public /**static**/ <T> T newProxy(Class<T> myInterfaces) {
ClassLoader classLoader = myInterfaces.getClassLoader();
Class<?>[] interfaces =new Class[]{myInterfaces};
//JdkProxy proxy =new JdkProxy();
return (T) Proxy.newProxyInstance(classLoader, interfaces, this); } @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return "123";
} }

这样就完成了;

测试。--> 结果是 123,   true(说明返回的对象是该接口的实现)

    public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:springTest/my.xml"); Object bean = app.getBean("testInterface");
System.out.println(bean);
System.out.println(bean instanceof TestInterface );
}

这样一个接口的代理就实现了,对于方法的调用需要在动态代理invoke 中下功夫;

Mybatis 是这样的话操作的,而dubbo 则是通过自定义标签的形式进行bean 的定义初始化,接口代理,原理与这个大同小异,具体请看我的以前文章,spring自定义标签的实现;

Mybatis 接口代理的实现(BeanDefinitionRegistryPostProcessor+FactoryBean)的更多相关文章

  1. MyBatis进阶--接口代理方式实现Dao 和动态SQL

    MyBatis接口代理方式实现Dao层 接口代理方式-实现规则 传统方式实现Dao层,我们既要写接口.还要写实现类.而MyBatis框架可以帮助我们省略写Dao层接口实现类的步骤.程序员只需要编写接口 ...

  2. Mybatis学习(2)原始dao开发和使用mapper接口代理开发

    基础知识: 1).SqlSessionFactoryBuilder: 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory.将SqlSessionFact ...

  3. Mybatis的dao层实现 接口代理方式实现规范+plugins-PageHelper

    Mybatis的dao层实现 接口代理方式实现规范 Mapper接口实现时的相关规范: Mapper接口开发只需要程序员编写Mapper接口而不用具体实现其代码(相当于我们写的Imp实现类) Mapp ...

  4. Mybatis源码解析5—— 接口代理

    本篇文章,可乐将为大家介绍通过接口代理的方式去执行SQL操作.话不多说,直接上图: 其实无论哪种方式,我们最终是需要找到对应的 SQL 语句,接口代理的方式就是通过 [包名.方法名] 的方式,去找到 ...

  5. MyBatis之代理开发模式

    1 mybatis-Dao的代理开发模式 Dao:数据访问对象 原来:定义dao接口,在定义dao的实现类 dao的代理开发模式 只需要定义dao接口,由mybatis产生dao接口的实现类. 1.1 ...

  6. 基于SSM之Mybatis接口实现增删改查(CRUD)功能

    国庆已过,要安心的学习了. SSM框架以前做过基本的了解,相比于ssh它更为优秀. 现基于JAVA应用程序用Mybatis接口简单的实现CRUD功能: 基本结构: (PS:其实这个就是用的Mapper ...

  7. Mybatis接口编程原理分析(三)

    前面两篇博客Mybatis接口编程原理分析(一)和Mybatis接口编程原理分析(二)我们介绍了MapperProxyFactory.MapperProxy和MapperMethod的操作及源码分析, ...

  8. Mybatis接口编程原理分析(二)

    在上一篇博客中 Mybatis接口编程原理分析(一)中我们介绍了MapperProxyFactory和MapperProxy,接下来我们要介绍的是MapperMethod MapperMethod:它 ...

  9. Mybatis接口编程原理分析(一)

    Mybatis接口编程示例 (1)首先定义接口编程需要的接口及其方法 public interface IUserMapper { public User getById(int id);//接口方法 ...

随机推荐

  1. window注册表相关

    参考: https://baike.baidu.com/item/REG_EXPAND_SZ/9102962 一 注册表的相关概念 windows注册表相关api中名字起的比较混乱, 在这放一张从网上 ...

  2. linux centos 中访问linux 共享文件方法

    mount -t cifs -o username="administrator",password="" //192.168.1.101/cp /mnt/nt ...

  3. C#实现json压缩和格式化

    json作为常用数据文件,为了传输的效率,在传输前要进行压缩,而在传输后要进行格式化,以便阅读.下面是使用C#完成的格式化和压缩代码. public static string Compress(st ...

  4. leetcode《按递增顺序显示卡牌》

    题目描述: 牌组中的每张卡牌都对应有一个唯一的整数.你可以按你想要的顺序对这套卡片进行排序. 最初,这些卡牌在牌组里是正面朝下的(即,未显示状态). 现在,重复执行以下步骤,直到显示所有卡牌为止: 从 ...

  5. Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView

    目标需求 实现一张小图片,被点击后变成一个在整个屏幕上显示的大图片.类似于微信朋友圈的图片. 实现流程 1.Fresco基本初始化 2.下载并且导入ZoomableDraweeView 它是实现大图的 ...

  6. Why the Anaconda command prompt is the first choice in windows?

    为什么在windows里,首选的conda命令行工具是Anaconda command prompt? In windows, what's the difference between comman ...

  7. 分布式之redis核心知识盘点?

    考虑到绝大部分写业务的程序员,在实际开发中使用redis的时候,只会setvalue和getvalue两个操作,对redis整体缺乏一个认知.又恰逢博主某个同事下周要去培训redis,所以博主斗胆以r ...

  8. eclipse启动tomcat正常,但是debug启动报错FATAL ERROR in native method:JDWP No transports initialized,jvmtiError=AGENT_ERROR_TRANSPORT_INIT(197) ERROR: transport error 202: connect failed:Connection timed out

    FATAL ERROR in native method:JDWP No transports initialized,jvmtiError=AGENT_ERROR_TRANSPORT_INIT(19 ...

  9. mybatis中两种取值方式?谈谈Spring框架理解?

    1.mybatis中两种取值方式? 回答:Mybatis中取值方式有几种?各自区别是什么? Mybatis取值方式就是说在Mapper文件中获取service传过来的值的方法,总共有两种方式,通过 $ ...

  10. 38_redux_counter应用_react版本

    redux的核心API 使用非redux创建: 项目结构: index.js import React from 'react'; import ReactDOM from 'react-dom'; ...