代理模式详解:静态代理、JDK动态代理与Cglib动态代理
- 代理模式简介分类 - 概念 -  代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑。 -  客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代理对象来实现的。当然,代理类与目标类需要实现同一个接口。 
- 举例 - 生活中遇到了官司,我们平常老百姓对法律的了解不全面,所以一般都会请律师处理。 - 目标对象:法庭上我们一般称为当事人即目标对象 - 代理类:律师称为代理律师即代理类 - 共同接口:都为了一个共同的目标努力赢得官司即为共同接口 - 目标方法:我们所做的提供证据各种努力成为目标方法 - 代理方法:再此过程中我们可能做不全面,律师对证据材料等进行整理收集,结合法律法规进行辩证等等,此过程称为代理方法 
- 代理分类 - 代理模式一般分为静态代理与动态代理,动态代理又分为JDK动态代理与CGLIB动态代理 
 
- 静态代理 - 概念 - 静态代理是指,代理类在程序运行前就已经定义好,其与目标类等关系在程序运行前就已经确立。 - 静态代理类似于富翁于私人律师的代理关系,并不是在发生官司之后才去请律师,而是在此之前已经确立好的代理关系。 
- 实现与解析 - a、定义业务接口 - package com.rangers.proxy.staticProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public interface IAccountService {
 // 转账业务接口
 void transfer();
 }
 - b、定义目标类与目标方法 - package com.rangers.proxy.staticProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class AccountServiceImpl implements IAccountService {
 // 转账业务实现即目标方法
 @Override
 public void transfer() {
 System.out.println("进行转账操作");
 }
 }
 - c、定义代理类AccountServiceImplProxy,实现IAccountService接口。在有参构造方法中传入目标对象,将目标对象引入代理类,以便代理类调用目标方法,进行增强 - package com.rangers.proxy.staticProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class AccountServiceImplProxy implements IAccountService { // 声明目标接口对象
 private IAccountService target; public AccountServiceImplProxy() {
 }
 // 业务接口对象作为构造器,用于接收目标对象
 public AccountServiceImplProxy(IAccountService target) {
 this.target = target;
 } @Override
 public void transfer() {
 // 此处对目标方法进行增强
 System.out.println("对转账人身份校验。。");
 target.transfer();
 System.out.println("进行日志记录。。");
 }
 }
 - d、编写测试类TransferServiceTest - package com.rangers.proxy.staticProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class TransferServiceTest {
 public static void main(String[] args) {
 // 创建目标对象
 IAccountService target = new AccountServiceImpl();
 // 创建代理对象,传入目标对象进行初始化
 IAccountService proxy = new AccountServiceImplProxy(target);
 // 执行代理对象的方法
 proxy.transfer();
 }
 }
 
 
- 动态代理 -  动态代理,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理工具在程序运行时由JVM根据反射等机制动态生成。代理对象与目标对象的代理关系在程序运行时才确立。 -  动态代理类似于普通人在有官司之后,再聘请律师的,即代理关系是在官司发生后确立的。 -  动态代理的实现方式有两种:JDK的动态代理、CGLIB动态代理 - a、JDK动态代理 - 概念 -  JDK动态代理是通过JDK提供的 java.lang.reflect.Proxy类实现动态大力,使用其静态方法newProxyInstance(),对目标对象、业务接口及业务增强逻辑,自动生成一个动态代理对象。 - public static newProxyInstance(ClassLoader classLoader,Class<?> interfaces,InvocationHandler handler)
 classLoader:传入目标类的类加载器,通过目标对象的反射获取
 interfaces:目标对象实现的接口数组,通过目标对象的反射获取
 handler:业务增强逻辑,需要具体实现
 -  InvocationHandler是个接口,实现InvocationHandler接口的类用于增加目标类的业务逻辑。需要实现invoke()方法,具体的增强逻辑就是在此方法中进行实现,程序调用住业务逻辑时会自动调用invoke()方法 - public Object invoke(Object proxy,Method method,Object[] args)
 proxy:生成的代理对象
 method:目标方法
 args:目标方法的参数
 -  Method类对象,invoke()方法进行执行目标对象的目标方法 - public Object invoke(Object obj,Object args)
 method.invoke(Object target,Object...args)执行目标方法
 target:目标对象
 args:目标方法的执行参数
 
- 实现与解析 - 定义业务接口与实现类
 - package com.rangers.proxy.jdkProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public interface IAccountService {
 // 转账业务接口
 void transfer();
 }
 - package com.rangers.proxy.jdkProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class AccountServiceImpl implements IAccountService {
 // 转账业务实现即目标方法
 @Override
 public void transfer() {
 System.out.println("进行转账操作");
 }
 }
 - 定义JdkProxy类实现InvocationHandler接口,实现invoke()方法,并对业务逻辑进行增强
 - package com.rangers.proxy.jdkProxy; import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class JdkProxy implements InvocationHandler { private Object target; public JdkProxy() {
 } public JdkProxy(Object target) {
 this.target = target;
 } @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 // 此处对目标方法进行增强
 System.out.println("对转账人身份校验。。");
 Object result = method.invoke(target, args);
 System.out.println("进行日志记录。。");
 return result;
 }
 }
 - 新建测试类JDKProxyTest
 - package com.rangers.proxy.jdkProxy; import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class JDKProxyTest {
 public static void main(String[] args) {
 // 创建目标对象
 IAccountService target = new AccountServiceImpl();
 // 创建代理对象,传入目标对象进行初始化
 IAccountService proxyService =
 (IAccountService) Proxy.newProxyInstance(
 target.getClass().getClassLoader(),
 target.getClass().getInterfaces(),
 new JdkProxy(target)
 );
 // 亦可使用匿名类进行实现
 /*(IAccountService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
 target.getClass().getInterfaces(), new InvocationHandler() {
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 // 此处对目标方法进行增强
 System.out.println("对转账人身份校验。。");
 Object result = method.invoke(target, args);
 System.out.println("进行日志记录。。");
 return result;
 }
 });*/
 // 此处执行的业务方法就是代理对象的增强过的逻辑
 proxyService.transfer();
 }
 }
 
 - 注:使用JDK动态代理时需要目标类目标方法必须在实现的接口中,否则不能使用此方式进行动态打击。对于无接口的类需要实现动态代理,就要使用CGLIB方式来进行实现 - b、CGLIB动态代理 - 概念 -  CGLIB是一个开源的第三方代码生成类库,对于无接口的类,要为其创建动态代理,就要使用CGLIB进行实现。CGLIB代理的生成原理是生成目标类的子类,子类是增强过的,就是目标类的代理类。所以,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final修饰的类。 -  CGLIB包的底层是通过使用一个小儿快的字节码处理框架ASM(java字节码操控框架),来转换字节码并生成新的类,通过对字节码进行增强来生成代理类。 -  我们静态代理理解为私人律师,JDK动态代理成为代理律师,CGLIB动态代理可以理解为老父亲的儿子。老父亲是被需要增强对目标类,儿子则是用于增强父亲对代理类,事先不需要约定。父亲需要儿子增强什么,儿子就增强什么,即他们之间的关系不要接口来进行约束。 
- 注意要点 - 使用CGLIB动态代理时,生成代理类的类需要实现MethodInterceptor接口及intercept()方法 - public Object intercept(Object proxy,Method method,Objectp[] args,MethodProxy methodProxy)
 proxy:代理对象
 method:代理对象的方法,即增强后的方法
 args:方法参数
 methodProxy:代理方法的对象
 - 创建代理对象时使用Enhancer类 - // 创建增强器
 Enhancer enhancer = new Enhancer();
 // 初始化增强器:将目标类指定为父类
 enhancer.setSuperclass(target.class);
 // 初始化增强器:设置回调至本类中的intercept()方法
 enhancer.setCallback(this);
 // 使用增强器创建代理对象进行返回
 enhancer.create();
 
- 实现与解析 - 引入CGLIB依赖 - <dependency>
 <groupId>cglib</groupId>
 <artifactId>cglib-full</artifactId>
 <version>2.0.2</version>
 </dependency>
 
- 创建目标类AccountService - package com.rangers.proxy.cglibProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class AccountService { // 转账业务 即目标方法
 public void transfer() {
 System.out.println("进行转账操作");
 } // 查询余额 即目标方法
 public void getBalance() {
 System.out.println("查询余额操作");
 }
 }
 
- 创建代理类AccountServiceCglibProxy实现MethodInterceptor接口,完善intercept()方法进行增强,创建生成代理对象createProxy()方法 - package com.rangers.proxy.cglibProxy; import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.MethodInterceptor;
 import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class AccountServiceCglibProxy implements MethodInterceptor { // 声明目标类的成员变量,并创建以目标类为参数的构造器,用于接收目标对象
 private AccountService target; public AccountServiceCglibProxy(AccountService accountService) {
 this.target = accountService;
 } @Override
 public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
 // 此处对目标方法进行增强
 Object result = new Object();
 if ("transfer".equals(method.getName())){
 System.out.println("对转账人身份校验。。");
 result = method.invoke(target, args);
 System.out.println("进行日志记录。。");
 }else{
 // 直接执行目标对象的目标方法
 result = methodProxy.invokeSuper(target,args);
 }
 return result;
 } // 创建代理对象
 public AccountService createProxy(){
 // 创建增强器
 Enhancer enhancer = new Enhancer();
 // 初始化增强器:将目标类指定为父类
 enhancer.setSuperclass(AccountService.class);
 // 初始化增强器:设置回调至本类中的intercept()方法
 enhancer.setCallback(this);
 // 使用增强器创建代理对象
 return (AccountService) enhancer.create();
 }
 }
 
- 创建测试类CglibProxyTest - package com.rangers.proxy.cglibProxy; /**
 * @Author Rangers
 * @Description
 * @Date 2021-03-09
 **/
 public class CglibProxyTest {
 public static void main(String[] args) {
 // 目标对象
 AccountService target = new AccountService();
 // 创建代理对象,传入目标对象进行初始化
 AccountService accountService = new AccountServiceCglibProxy(target).createProxy();
 accountService.transfer();
 accountService.getBalance();
 }
 }
 
 
 
代理模式详解:静态代理、JDK动态代理与Cglib动态代理的更多相关文章
- 代理模式详解:静态代理+JDK/CGLIB 动态代理实战
		1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ... 
- Docker Kubernetes  Service 网络服务代理模式详解
		Docker Kubernetes Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ... 
- 代理模式之静态代理,JDK动态代理和cglib动态代理
		代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ... 
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
		Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ... 
- java的静态代理、jdk动态代理和cglib动态代理
		Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ... 
- Spring 静态代理+JDK动态代理和CGLIB动态代理
		代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ... 
- 【转】java的动态代理机制详解
		java的动态代理机制详解 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们 ... 
- Java代理:静态代理、JDK动态代理和CGLIB动态代理
		代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式.所谓的代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.存储器中的大对象.文件或其它昂贵或无法复制 ... 
- [转载] java的动态代理机制详解
		转载自http://www.cnblogs.com/xiaoluo501395377/p/3383130.html 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代 ... 
随机推荐
- 避坑!js正确地使用fill()初始化二维数组
			先介绍一下坑 fill()方法都知道,填充数组 比如: let a = new Array(5).fill(0); console.log(a); // 输出结果为[0, 0, 0, 0, 0] 当我 ... 
- Dapr 已在塔架就位 将发射新一代微服务
			微服务是云原生架构的核心,通常使用Kubernetes 来按需管理服务扩展. 微软一直走在 Cloud Native Computing Foundation的 最前沿,并通过使用Kubernetes ... 
- Python小练习批量爬取下载歌曲
			import requests import os headers={ 'Cookie': '_ga=GA1.2.701818100.1612092981; _gid=GA1.2.748589379. ... 
- cin的用法
			int val=0; cin>>val; 上述程序先定义了一个整型数据val,通过cin读取数据放在val中,如果输入的整型数据,则读取成功,返回的是>>左侧的对象,也就是is ... 
- P4213 【模板】杜教筛(杜教筛)题解
			题意: 求\(\sum_{i=1}^n\varphi(i)\)和\(\sum_{i=1}^n\mu(i)\) 思路: 由性质可知:\(\mu*I=\epsilon,\varphi*I=id\)那么可得 ... 
- 洛谷p1637 三元上升子序列(树状数组
			题目描述 Erwin最近对一种叫"thair"的东西巨感兴趣... 在含有n个整数的序列a1,a2......an中, 三个数被称作"thair"当且仅当i&l ... 
- HTML5 Animation Creator | Hype 官方文档
			HTML5 Animation Creator | Hype 官方文档 HTML5 Animation Build 7个 专业术语 场景,元素,属性,关键帧,动画,时间线,操作 Hype 官方文档 h ... 
- GitHub for VSCode
			GitHub for VSCode A first-party GitHub OAuth application (GitHub for VSCode) with repo and workflow ... 
- Node.js & LTS
			Node.js & LTS 2020 https://nodejs.org/en/about/releases/ https://raw.githubusercontent.com/nodej ... 
- django学习-5.获取url参数和name的作用
			1.前言 假如我们要打开这两个博客园地址:[https://www.cnblogs.com/xiamen-momo/archive/2020/11.html].[https://www.cnblogs ... 
