Mybatis 接口代理的实现(BeanDefinitionRegistryPostProcessor+FactoryBean)
相信在开发中,尤其是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)的更多相关文章
- MyBatis进阶--接口代理方式实现Dao 和动态SQL
MyBatis接口代理方式实现Dao层 接口代理方式-实现规则 传统方式实现Dao层,我们既要写接口.还要写实现类.而MyBatis框架可以帮助我们省略写Dao层接口实现类的步骤.程序员只需要编写接口 ...
- Mybatis学习(2)原始dao开发和使用mapper接口代理开发
基础知识: 1).SqlSessionFactoryBuilder: 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory.将SqlSessionFact ...
- Mybatis的dao层实现 接口代理方式实现规范+plugins-PageHelper
Mybatis的dao层实现 接口代理方式实现规范 Mapper接口实现时的相关规范: Mapper接口开发只需要程序员编写Mapper接口而不用具体实现其代码(相当于我们写的Imp实现类) Mapp ...
- Mybatis源码解析5—— 接口代理
本篇文章,可乐将为大家介绍通过接口代理的方式去执行SQL操作.话不多说,直接上图: 其实无论哪种方式,我们最终是需要找到对应的 SQL 语句,接口代理的方式就是通过 [包名.方法名] 的方式,去找到 ...
- MyBatis之代理开发模式
1 mybatis-Dao的代理开发模式 Dao:数据访问对象 原来:定义dao接口,在定义dao的实现类 dao的代理开发模式 只需要定义dao接口,由mybatis产生dao接口的实现类. 1.1 ...
- 基于SSM之Mybatis接口实现增删改查(CRUD)功能
国庆已过,要安心的学习了. SSM框架以前做过基本的了解,相比于ssh它更为优秀. 现基于JAVA应用程序用Mybatis接口简单的实现CRUD功能: 基本结构: (PS:其实这个就是用的Mapper ...
- Mybatis接口编程原理分析(三)
前面两篇博客Mybatis接口编程原理分析(一)和Mybatis接口编程原理分析(二)我们介绍了MapperProxyFactory.MapperProxy和MapperMethod的操作及源码分析, ...
- Mybatis接口编程原理分析(二)
在上一篇博客中 Mybatis接口编程原理分析(一)中我们介绍了MapperProxyFactory和MapperProxy,接下来我们要介绍的是MapperMethod MapperMethod:它 ...
- Mybatis接口编程原理分析(一)
Mybatis接口编程示例 (1)首先定义接口编程需要的接口及其方法 public interface IUserMapper { public User getById(int id);//接口方法 ...
随机推荐
- [SQL]事务回滚详解及示例
存储过程中的 SET XACT_ABORT ON 和事务 在存储过程中写SET XACT_ABORT ON 有什么用? SET XACT_ABORT ON是设置事务回滚的! 当为ON时,如果你存储中的 ...
- 机器学习笔记之三-yolov3+win7+vs2017+gpu+opencv编译
1.环境安装 1.1 vs2017+cuda9.1+cudnn7.0可以和tensorflow一起安装网上教程多,不多说. 唯一需要注意的是vs2017要安装好2015版本的工具集v140 ...
- 理解Linux文件权限
任何完整的系统都应该具备有某种形式的安全性.必须用过某种机制来保护文件不被未授权的用户查看或修改:Linux系统遵循了Unix的文件权限的方法,来根据用户与用户组授权,实现文件安全访问. 1.Linu ...
- python使用selenium爬百度文库ppt并生成pdf
详细的讲解我是写在另外一个网址:https://www.yuque.com/docs/share/aacfa45c-22c5-4ef6-be97-cd6849002274 有点尬尴,所以就..... ...
- C 语言 判断
if if (im < 0) { im = 60 + im; ih--; } 如果 (im < 0) 小于零,那么 做{ } 中内容 如果 (im < 0) 不小于零,那么 { }中 ...
- (6.1)linux操作系统基础
Linux介绍: Linux是一种自由和开放源码的操作系统,存在着许多不同的Linux版本,但它们都使用了Linux内核.Linux可安装在各种计算机硬件设备中,比如手机.平板电脑.路由器.台式计算机 ...
- 嵌入式linux——汇编、C语言基础(一)
一.汇编语言基础 (断断续续的记录自己的笔记...2018-10-11) 1. mov指令 基本用法: mov r0, #0 mov指令是赋值指令,用法如上,把立即数0放入到寄存器r0中. 2. bl ...
- mockito 异常Reason: java.io.IOException: invalid constant type: 18
原因: mockito内部使用的javassit的版本不一致导致的,修改为一直版本即可. 异常内容: /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jd ...
- Django上传文件和上传图片(不刷新页面)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- sybase的ASE和IQ版本有什么区别
原文:ASE是sybase OLTP数据库,行式存储.IQ是Sybase OLAP和DSS的数据库,采用列式存储,适合数据仓库.数据集市等分析性应用,不符合并发压力大的联机场景.