动态代理的理解

一:动态代理和静态代理的区别

静态代理:了解设计模式中的代理模式的童鞋应该都知道,如果想要生成代理类,需要让代理类和被代理类实现同一个接口,并且在代理类中添加被代理类的引用,代理类方法实现中添加代理逻辑,并决定是否调用被代理类方法,这种通过硬编码的方式指定代理类与被代理类的方式,叫静态代理。可以明显看出,静态代理类与被代理类是强耦合的,如果要代理100个类,你就得写100个代理类
动态代理:其实动态代理与静态代理的本质一样,最终程序运行时都需要生成一个代理对象实例,通过它来完成相关增强以及业务逻辑,只不过静态代理需要硬编码的方式指定,而动态代理则是以动态方式生成代理(有编译时操作字节码生成的方式、运行时通过反射、字节码生成的方式)。动态生成的好处很明显,代理逻辑与业务逻辑是互相独立的,没有耦合,代理1个类或100个类要做的事情没有任何区别

说到耦合,必须把AOP拿来说道说道:传统面向对象思想中,如果想要实现功能复用,要么继承、要么引用,无论哪种方式,对代码都有一定的侵入性,耦合无可避免,侵入性啥意思?简单来说:如果你想要用它增强你程序的功能,你必须改动你的程序代码,那它就具有侵入性。如果只有一点两点需要增强还好说,如果大量的功能点需要被增强,工作量就会很大,代码也不太优雅。想象一下,如果你对外公开了一系列的接口,现在领导说了,接口要加权限控制。在哪加?最笨的当然就是写个程序验证的逻辑,然后每个接口都拿来调用一遍。这也正是面向对象思想的短板,在要为程序新增一些通用功能时,只能通过耦合的方式才能进行。AOP正是为此而生,AOP旨在通过一种无耦合的方式来为程序带来增强。而动态代理,就是AOP实现方式中的一种

二:动态代理相关的类

Proxy:生成动态代理的实例
InvocationHandler:
每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。(invoke()方法可以通过反射加载被代理的类的方法)

三:代码实现

1:接口

package com.wyj.demo03;public interface UserService {void deleteUser();void addUser();void updateUser();void selectUser();
}

2:实现类

package com.wyj.demo03;import com.wyj.demo03.UserService;public class UserServiceImp implements UserService {@Overridepublic void deleteUser() {System.out.println("删除一个用户");}@Overridepublic void addUser() {System.out.println("增加一个用户");}@Overridepublic void updateUser() {System.out.println("修改一个用户");}@Overridepublic void selectUser() {System.out.println("查询一个用户");}
}

3:生成动态代理类的程序

package com.wyj.demo03;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//生成代理类的程序
public class ProxyInvocationHandler implements InvocationHandler {//被代理的类private Object target;//设置要代理的类(这个就是我们具体要代理的类)public void setTarget(Object target) {this.target = target;}//生成得到代理类(这里我们返回的是一个接口 也就是被代理的类 所实现的接口)public Object getProxy() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}/**** @param proxy :被代理的对象* @param method:被代理的对象的方法* @param args :被代理的对象的参数* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log(method.getName());Object invoke = method.invoke(target, args);//在反射中通过 方法名.invoke(类名);传统方法中 类名.方法名();return invoke;}//增加需求 打印日志public void log(String msg) {System.out.println("调用了"+msg);}
}

其中的参数解析
类加载机制:
首先我们要了解一下类的加载机制,在每创建一个Java类时,都会生产一个.class文件,在内存中对应也会生成一个class对象,来表示该类的类型信息,我们可以用.class来获取这个类的所有信息,也可以通过getClass()方法来读取这个类的所有信息,比如getClass().getInterfaces()获取类的接口信息等。在Java类加载时,要通过一个类加载器classloader来将生成的Java类加载到JVM中才能执行。理解了类的加载机制后,我们再看代码中的newProxyInstance方法,在这个方法中,我们将被代理对象传进来后.
在这里插入图片描述

在Proxy.newProxyInstance方法中,共有三个参数:
1、target.getClass().getClassLoader()目标对象通过getClass方法获取类的所有信息后,调用getClassLoader()方法来获取类加载器。获取类加载器后,可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要!
2、target.getClass().getInterfaces()获取被代理类的所有接口信息,以便于生成的代理类可以具有代理类接口中的所有方法。
3、this:我们使用动态代理是为了更好的扩展,比如在方法之前做什么,之后做什么等操作。这个时候这些公共的操作可以统一交给代理类去做。这个时候需要调用实现了InvocationHandler 类的一个回调方法。由于自身实现了这个方法,所以将this传递过去。
(也就是在这个ProxyInvocationHandler 类自身中实现一些需求的方法)

4:实现过程

package com.wyj.demo03;public class Client {public static void main(String[] args) {//真实角色UserServiceImp serviceImp = new UserServiceImp();//代理角色不存在ProxyInvocationHandler handler = new ProxyInvocationHandler();//设置被代理的对象handler.setTarget(serviceImp);//得到代理类对象(这个是我们返回是一个接口,我们的被代理类是实现的一个接口)UserService proxy = (UserService) handler.getProxy();proxy.deleteUser();}
}

实现过程的解析:
代理类是在运行时创建的实现指定的接口列表(称为代理接口)的类 。
代理实例(proxy)是代理类的一个实例。 每个代理实例(proxy)都有一个关联的调用处理程序对象(handler),它实现接口InvocationHandler 。
通过其代理接口之一的代理实例上的方法,调用将被分派到实例调用处理程序的invoke方法,传递代理实例,标识调用方法的java.lang.reflect.Method对象以及包含参数的类型为Object的数组。 调用处理程序适当地处理编码方法调用,并且返回的结果将作为方法在代理实例上调用的结果返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET Core 下的爬虫利器

爬虫大家或多或少的都应该接触过的,爬虫有风险,抓数需谨慎。本着研究学习的目的,记录一下在 .NET Core 下抓取数据的实际案例。爬虫代码一般具有时效性,当我们的目标发生改版升级,规则转换后我们写的爬虫代码就会失效&…

Redux从入门到进阶,看这一篇就够了!

Redux,带你从入门到进阶🌂序言☂️一、基础知识1、Redux概念简述2、Redux的工作流程🎃二、使用Antd实现TodoList页面布局1、在项目中使用Antd2、使用Antd实现TodoList的基本布局3、创建redux中的store(1)创建store&…

ASP.NET Core 3.x控制IHostedService启动顺序浅探

想写好中间件,这是基础。一、前言今天这个内容,基于于ASP.NET Core 3.x。从3.x开始,ASP.NET Core使用了通用主机模式。它将WebHostBuilder放到了通用的IHost之上,这样可以确保Kestrel可以运行在IHostedService中。我们今天就来研究…

com.mysql.cj.exceptions.InvalidConnectionAttributeException

一:java连接数据库报错 com.mysql.cj.exceptions.InvalidConnectionAttributeException 二:报错原因 MySQL jdbc 6.0 版本以上必须配置“serverTimezone”参数 UTC代表的是全球标准时间 若我们使用的时间是北京时区也就是东八区,领先UTC八个小时。url的时区使用…

Istio Pilot 源码分析(一)

张海东, ‍多点生活(成都)云原生开发工程师。Istio 作为目前 Servic Mesh 方案中的翘楚,吸引着越来越多的企业及开发者。越来越多的团队想将其应用于微服务的治理,但在实际落地时却因为不了解 Istio 黑盒中的运行机制而…

结营啦!有缘相聚于青训,未来高处见呀~~

📸叮! 记 字节跳动第一届青训营顺利结营啦! 从8月份的青训营,到9月份的实训营,搁置了许久的结营心得终于拾起来辽! 🎬开营进行时 从答疑会开始,负责人仔细的阐述了本次训练营的…

MVC三层架构(详解)

1:初始MVC (1):三层架构 三层架构是指:视图层 View、服务层 Service,与持久层 Dao。它们分别完成不同的功能。 View 层:用于接收用户提交请求的代码在这里编写。 Service 层:系统的业务逻辑主要在这里完成。 Dao 层:…

「offer来了」保姆级巩固你的js知识体系(4.0w字)

「面试专栏」前端面试之JavaScript篇🧐序言🥳思维导图环节😏一、JS规范1、说几条JavaScript的基本规范。2、对原生JavaScript的了解。3、说下对JS的了解吧。4、JS原生拖拽节点5、谈谈你对ES6的理解6、知道ES6的class嘛?7、说说你对…

写作是人生最大的杠杆

职场&认知洞察 丨 作者 / 易洋 这是findyi公众号的第71篇原创文章不知不觉,公众号写作已经持续了9个月了。去年11月底,心血来潮写了第一篇文章,更多是为了复盘过去的一些工作经历。在前几天,读者数突破了3万,虽然…

拥塞控制(详解)

一:TCP的拥塞控制 1:是什么 (1):是什么(拥塞现象) 网络的 吞吐量 与 通信子网 负荷(即通信子网中正在传输的分组数)有着密切的关系。当 通信子网 负荷比较小时,网络的 吞吐量 (分组数/秒)随网络负荷(每个 节点 中分组的平均数)的增加而线性增加。当网络负荷增加到…

解决 WPF 绑定集合后数据变动界面却不更新的问题(使用 ObservableCollection)

解决 WPF 绑定集合后数据变动界面却不更新的问题独立观察员 2020 年 9 月 9 日在 .NET Core 3.1 的 WPF 程序中打算用 ListBox 绑定显示一个集合(满足需求即可,无所谓什么类型的集合),以下是 Xaml 代码(瞟一眼就行&…

Kubernetes Liveness and Readiness Probes

在设计关键任务、高可用应用程序时,弹性是要考虑的最重要因素之一。当应用程序可以快速从故障中恢复时,它便具有弹性。云原生应用程序通常设计为使用微服务架构,其中每个组件都位于容器中。为了确保Kubernetes托管的应用程序高可用&#xff0…

「offer来了」2种递进学习思维,24道计网题目,保姆级巩固你的计网知识体系

「面试专栏」前端面试之计算机网络篇⚾序言🏐一、基础知识环节1、专栏学习2、书籍学习⚽二、思维导图环节🎳三、OSI七层模型1、OSI模型是什么?2、OSI七层模型遵循原则🏏四、TCP与UDP1、TCP与UDP的区别2、TCP/UDP的优缺点&#xff…

leetcode236. 二叉树的最近公共祖先

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:/**思路:1.这里我们需要的是从底向上开…

进击吧! Blazor !第二期 页面制作

Blazor 是一个 Web UI 框架,可通过 WebAssembly 在任意浏览器中运行 .Net 。Blazor 旨在简化快速的单页面 .Net 浏览器应用的构建过程,它虽然使用了诸如 CSS 和 HTML 之类的 Web 技术,但它使用 C#语言和 Razor 语法代替 JavaScrip…

「软件项目管理」一文详解软件项目管理概述

一文详解软件项目管理概述🚵前言🤽一、项目与软件项目1、项目的定义2、项目的特征3、项目与日常运作举例(1)判断哪些活动是项目(2)举例结果(3)项目与日常运作区别总结4、软件项目的特…

初识ABP vNext(9):ABP模块化开发-文件管理

点击上方蓝字"小黑在哪里"关注我吧创建模块模块开发应用服务运行模块单元测试模块使用前言在之前的章节中介绍过ABP扩展实体,当时在用户表扩展了用户头像字段,用户头像就涉及到文件上传和文件存储。文件上传是很多系统都会涉及到的一个基础功能…

「offer来了」浏览器原理被问懵?5大知识板块巩固你的http知识体系(3.6w字)

「面试专栏」前端面试之浏览器原理篇🏔️序言🌄一、http和https协议(一)http和https之间的关系🧭1、http和https是什么?2、http和https的区别(二)http协议🧭1、http1.0、…

使用Azure DevOps Pipeline实现.Net Core程序的CD

上一次我们讲了使用Azure DevOps Pipeline实现.Net Core程序的CI。这次我们来演示下如何使用Azure DevOps实现.Net Core程序的CD。实现本次目标我们除了Azure DevOps外还需要:一台安装了Docker的主机一个 Docker Hub 账号上一次我们的CI实现了:发布>编…

TCP四次挥手(详解)

一:TCP四次挥手 1:图示 二:TCP四次挥手的过程 所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。挥手之前主动释放连接的客户端结束ESTABLISHED阶段。随后开始“四次挥手”: a:首先客户端想要释放连接&#xff0c…