Mybatis 接口代理的实现

相信在开发中,尤其是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自定义标签的实现;

原文地址:https://www.cnblogs.com/iscys/p/10023831.html

时间: 2024-07-31 01:33:13

Mybatis 接口代理的实现的相关文章

【转】MyBatis接口的简单实现原理

MyBatis接口的简单实现原理 用过MyBatis3的人可能会觉得为什么MyBatis的Mapper接口没有实现类,但是可以直接用? 那是因为MyBatis使用Java动态代理实现的接口. 这里仅仅举个简单例子来说明原理,不是完全针对MyBatis的,这种思想我们也可以应用在其他地方. 定义一个接口 public interface MethodInterface { String helloWorld(); } 实现动态代理接口 public class MethodProxy<T> im

java框架---MyBatis接口编程

MyBatis提供接口与配置文件动态绑定的功能 要求: 1.配置文件的namespace名称空间指定为接口的全类名 2.配置文件中的id唯一标识与接口中的方法对应(返回值类型对应,方法名对应,参数个数和类型对应) 接口代码: package com.bird.mybatis.dao; import com.bird.mybatis.bean.Employee; public interface EmployeeMapper { public Employee getEmpById(Integer

使用nginx作为webservice接口代理

通常情况下,企业并不会直接开放系统接口给到外网,并且在企业内部同样有SOA或者ESB这样的接口统一管理的工具. 那么,大多数情况下,如果需要与外部系统,如云系统,或者其他企业的系统做接口时采取的方式如下 企业内部业务系统接口<-->SOA/ESB<-->DMZ<-->外部系统 如果外部系统是其他企业的业务系统,可能同样会经过DMZ<-->SOA/ESB<-->业务系统接口的这样一个流程. 一方面,由于数据流转节点较多,需要做好整个流程中所有系统可

接口代理对象

为什么要接口代理? 在不改变原来代码,对已有方法增强 1 创建一个卖电脑接口 public interface SaleComputer { public String sale(double money); public void show(); } 2 创建一个类,实现接口 public class Lenovo implements SaleComputer { @Override public String sale(double money) { System.out.println(

Java EE开发平台随手记5——Mybatis动态代理接口方式的原生用法

为了说明后续的Mybatis扩展,插播一篇广告,先来简要说明一下Mybatis的一种原生用法,不过先声明:下面说的只是Mybatis的其中一种用法,如需要更深入了解Mybatis,请参考官方文档,或者研读源码. 我们知道,使用Mybatis的方式有很多种,从是否集成上分,可以单独使用,也可以和Spring集成使用:从使用方式上分,可以编写静态工具类,在静态工具中调用SqlSession,也可以直接注入SqlSession/ SqlSessionTemplate,还可以编写Dao接口,让mybat

Mybatis 映射器接口代理对象的方式 运行过程debug分析

查询一张表的所有数据. 环境: 使用工具IntelliJ IDEA 2018.2版本. 创建Maven工程不用骨架 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4.MyBatis Mapper代理开发方式(推荐使用)

1 Mapper代理开发方式(推荐) Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可.Mybatis会自动的为mapper接口生成动态代理实现类. 不过要实现mapper代理的开发方式,需要遵循一些开发规范. 1.1  Mapper开发规范 1. mapper接口的全限定名要和mapper映射文件的namespace的值相同. 2. mapper接口的方法名称要和mapper映射文件中的statement的id相同: 3. mapper接口的方法参数只能有一

6、Spring+Struts2+MyBatis(mybatis有代理)整合增删改查

1.创建如下的oracle脚本 1 create table userinfo 2 (id number(4), 3 name varchar2(50), 4 password varchar2(20 5 telephone varchar2(15), 6 isadmin varchar2(5)); 7 8 --4.2 用户表序列 9 create sequence seq_userinfo; 10 11 alter table userinfo add constraint pk_userin

Spring+Struts2+MyBatis+分页(mybatis无代理)增删改查

1.创建如下项目结构 2.在src下的com.entity包下创建Dept.java package com.entity; /** * 部门表 * @author CHIL * */ public class Dept { private Integer deptno; //部门编号 private String dname; //部门名称 private String loc; //位置 public Dept() { } public Dept(Integer deptno, String