mybatis 01: 静态代理 + jdk动态代理
背景
有时目标对象不可直接访问,只能通过代理对象访问
图示:

- 示例1:
- 房东 ===> 目标对象
- 房屋中介 ===> 代理对象
- 你,我 ===> 客户端对象
- 示例2:
- 运营商(电信,移动,联通) ===> 目标对象
- 第三方公司 ===> 代理对象
- 开发的应用程序需要发送短信的功能(或者需要支付功能) ===> 客户端对象
代理模式的作用
- 控制客户对目标对象的访问
- 增强访问功能
代理模式的分类
- 静态代理
- 动态代理
- JDK动态代理
- CGLib动态代理
静态代理
特点
- 目标对象和代理对象实现同一个业务接口
- 目标对象必须实现接口
- 代理对象在程序运行前就已经存在
静态代理示例与原理分析
业务背景

分析
- 定义业务接口:面向接口编程,定义业务
- 目标对象实现接口:业务的核心功能到底怎么实现
- 代理对象(扩展业务 + 核心业务)
- 实现了目标对象所实现的接口,说明代理对象有资历进行代理
- 对核心业务进行扩展
- 调用目标对象实现核心业务(只能目标对象自己完成)
- 客户:无法直接访问目标对象,要访问代理对象
代码实现
面向接口编程
- 成员变量是接口类型
- 传入目标对象,方法的参数设计为接口
- 调用时,接口指向实现类
静态代理对象代码
package com.example.service.impl; import com.example.service.Service; public class Agent implements Service { //定义接口对象
public Service target; public Agent(){} //传入接口对象
public Agent(Service target){
this.target = target;
} @Override
public void sing() {
System.out.println("协商演出时间......");
System.out.println("协商演出地点......"); //目标对象完成核心业务,接口指向实现类,调用实现类的方法
target.sing(); System.out.println("协商演出费用......");
}
}
静态代理优缺点
- 优点:能够灵活的进行目标对象的切换
- 适用于业务固定,目标对象可灵活切换的场景
- 缺点:无法进行功能的灵活处理,当业务发生改变时,所有涉及到的实现类代码和代理对象代码都要改变
动态代理
JDK动态代理
特点
- 目标对象必须实现业务接口
- JDK代理对象不需要实现业务接口
- JDK代理对象在程序运行前不存在,程序运行时动态的在内存中构建(根据受代理的对象动态创建)
- JDK动态代理可以灵活的进行业务功能的切换
JDK动态代理用到的类和接口
- 使用现有的工具类完成JDK动态代理
- 先了解两个单词的意思
- InvocationHandler:调用处理程序
- invoke:调用
Method类
- 反射时用的类,用来进行目标对象的目标方法的反射调用
- method对象,接住我们正在调用的方法 sing(),show()
- method == sing(),show(),即:待调用的方法
- method.invoke() ==> 相当于手工调用目标方法 sing(),show();
InvocationHandler接口
- 用来实现代理和业务功能,我们在调用时使用匿名内部实现
- 匿名内部实现:new接口的同时,重写接口中的方法(相当于定义了该接口的一个实现类)
Proxy类
位于:java.lang.reflect.Proxy包下
有一个核心方法:Proxy.newProxyInstance(....),专门获取动态代理对象,有三个参数
参数1:ClassLoader loader
- 目标对象的类加载器
- 目的:获取类方法等信息,毕竟底层还是要调用受代理对象所实现的方法
- 传入:targetObj.getClass().getClassLoader();
参数2:Class<?>[] interfaces
- 目标对象实现的所有接口,类的接口可以有多个
- 目的:获取目标对象实现的所有接口以及接口的相关信息,毕竟底层要知道目标对象都可以完成哪些业务操作
- 传入:targetObj.getClass().getInterfaces();
上面两个参数为代理对象动态的创建和调用目标对象的方法提供了数据支持,第3个参数相当于调用程序
参数3:InvocationHandler
- 实现代理功能的接口,这里代理功能包括:扩展的功能 + 核心业务功能,传入的匿名内部实现如下
new InvocationHandler() {
@Override
public Object invoke(
Object obj,
//用来反射调用方法
Method method,
//待调用方法需要的参数
Object[] args)
throws Throwable { //扩展业务
System.out.println("协商演出时间......");
System.out.println("协商演出地点......"); //核心业务,具体调用什么方法根据外层业务来反射调用对应方法
Object res = method.invoke(target, args); //扩展业务
System.out.println("协商演出费用......"); //目标对象执行的目标方法的返回值
return res;
}
}
JDK动态代理示例
代理工厂代码
package com.example.proxy; import com.example.service.Service; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyFactory {
//目标对象
Service target; public ProxyFactory(){} public ProxyFactory(Service target){
this.target = target;
} //返回代理对象
public Object getAgent(){
return Proxy.newProxyInstance(
//需要知道受代理对象的类信息
target.getClass().getClassLoader(),
//需要知道受代理对象实现的所有接口信息
target.getClass().getInterfaces(),
//反射调用目标对象的目标方法
new InvocationHandler() {
@Override
public Object invoke(
Object obj,
//用来反射调用方法
Method method,
//待调用方法需要的参数
Object[] args)
throws Throwable { //扩展业务
System.out.println("协商演出时间......");
System.out.println("协商演出地点......"); //核心业务,具体调用什么方法根据外层业务来反射调用对应方法
Object res = method.invoke(target, args); //扩展业务
System.out.println("协商演出费用......"); //目标对象执行的目标方法的返回值
return res;
}
}
);
}
}
测试代码示例
package com.example.proxy; import com.example.service.Service;
import com.example.service.impl.SuperStarZhou;
import org.junit.Test; public class TestProxyFactory {
@Test
public void testGetProxy(){
//确定客户需求
ProxyFactory factory = new ProxyFactory(new SuperStarZhou());
//根据需求动态返回对应类型的代理对象
Service agent = (Service) factory.getAgent();
//依托对应类型的动态代理对象完成业务:扩展业务(动态代理对象完成) + 核心业务(目标对象完成)
agent.sing();
} @Test
public void testGetProxy2(){
ProxyFactory factory = new ProxyFactory(new SuperStarZhou());
Service agent = (Service) factory.getAgent();
String res = (String) agent.show(60);
System.out.println(res);
}
}
注意
可被代理的方法应该是受代理对象实现的所有接口中的方法与其所有实体方法的交集
- 本类中独有的方法不被代理
类型的转变
@Test
public void testGetProxy2() {
ProxyFactory factory = new ProxyFactory(new SuperStarZhou());
Service agent = (Service) factory.getAgent();
Service liu = new SuperStarLiu();
System.out.println("类型1: " + liu.getClass());
System.out.println("类型2: " + agent.getClass());
}
/*
输出结果:
类型1: class com.example.service.impl.SuperStarLiu
类型2: class com.sun.proxy.$Proxy7
*/
mybatis 01: 静态代理 + jdk动态代理的更多相关文章
- 从Mybatis源码理解jdk动态代理默认调用invoke方法
一.背景最近在工作之余,把开mybatis的源码看了下,决定自己手写个简单版的.实现核心的功能即可.写完之后,执行了一下,正巧在mybatis对Mapper接口的动态代理这个核心代码这边发现一个问题. ...
- Java的三种代理模式:静态代理/JDK动态代理/Cglib动态代理
1.静态代理:需要定义接口或者父类,目标对象与代理对象均实现同一接口或继承同一父类. 2.JDK动态代理:需要目标对象实现一个接口,通过动态反射的机制,生成代理对象,实现同一个接口 3.Cglib动态 ...
- java 静态代理 JDK动态代理 Cglib动态代理
下面以一个简单的银行账户为例讲述讲述动态代理. 设计一个银行账户类,包含用户的账户余额,实现查询和更新余额功能 这个系统用了一段时间,有客户要求对账说账户余额给弄错了?因为上面没有存取款记录,最后银行 ...
- MyBatis之反射技术+JDK动态代理+cglib代理
一.反射 引用百度百科说明: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功 ...
- 【Java入门提高篇】Day11 Java代理——JDK动态代理
今天来看看Java的另一种代理方式--JDK动态代理 我们之前所介绍的代理方式叫静态代理,也就是静态的生成代理对象,而动态代理则是在运行时创建代理对象.动态代理有更强大的拦截请求功能,因为可以获得类的 ...
- 动态代理 JDK动态代理 CGLIB代理
代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法.实际执行的是被代理类的方法. 而AOP,是通过动态代理实现的. 一.简单来说: JD ...
- 代理-jdk动态代理
1.基于接口的实现,要jdk动态代理的类必须要实现一个接口: 2.中介类:实现了InvocationHandler,并重写这个接口的 方法(public Object invoke(Object pr ...
- MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析
我们以往使用ibatis或者mybatis 都是以这种方式调用XML当中定义的CRUD标签来执行SQL 比如这样 <?xml version="1.0" encoding=& ...
- 017 Java中的静态代理、JDK动态代理、cglib动态代理
一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...
随机推荐
- Spring Boot配置全局异常捕获
1 SpringBoot配置全局的异常捕获 项目的说明 配置thymeleaf作为视图模板 ExceptionController.java模拟测试用 MyAjaxExceptionHandler.j ...
- [持续更新] Python学习、使用过程中遇见的非代码层面知识(想不到更好的标题了 T_T)
写在前面: 这篇博文记录的不是python代码.数据结构.算法相关的内容,而是在学习.使用过程中遇见的一些没有技术含量,但有时很令人抓耳挠腮的小东西.比如:python内置库怎么看.python搜索模 ...
- 使用argparse进行调参
argparse是深度学习项目调参时常用的python标准库,使用argparse后,我们在命令行输入的参数就可以以这种形式python filename.py --lr 1e-4 --batch_s ...
- 【ASP.NET Core】配置应用程序地址的N多种方法
下面又到了老周误人子弟的时间,今天要误大伙的话题是:找找有多少种方法可以设置 ASP.NET Core 应用的地址,即 URL. 精彩马上开始! 1.UseUrls 方法 这是一个扩展方法,参数是可变 ...
- linux运维基础1
内容概要 运维简介 运维岗位职责 服务器 服务器硬件介绍 磁盘阵列 虚拟化软件及环境 虚拟化软件 安装操作系统 Vmware虚拟机安装及相关配置流程 内容详情 运维简介 运维岗位职责 核心:运行维护应 ...
- 阶段性总结 GDOI 2022 PJ
阶段性总结 GDOI 2022 PJ 比赛经过 Day ? ~ Day -1 半停课集训,补了很多东西,但是之前漏得太多了,结果是还有很多题没改 打了若干场 AtCoder ,承认自己思维的不足,训练 ...
- python实现对简单的运算型验证码的识别【不使用OpenCV】
最近在写我们学校的教务系统的手机版,在前端用户执行绑定操作后,服务器将执行登录,但在登录过程中,教务系统中有个运算型的验证码,大致是这个样子的: 下面我们开始实现这个验证码的识别. 1.图片读取 从网 ...
- 物联网lora模块应用案例和LoRawan网关通信技术
什么是LoRa LoRa(Long Range) 无线通信技术是 Semtech 在2012年开发出来的一款适合物联网使用的射频IC.其设计理念为低功耗.长距离.低成本.网路简单.易于扩展的无线数传技 ...
- 【转载】解决k8s中的长连接负载均衡问题
原文链接:一流铲屎官二流程序员[解决k8s中的长连接负载均衡问题] 长连接与短连接: 简介 长连接是指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测 ...
- Linux如何安装JDK1.8版本详细步骤
Linux如何安装JDK1.8版本详细步骤 1.下载JDK1.8版本压缩包 进入官网:https://www.oracle.com/java/technologies/downloads/ 2.将压缩 ...