什么是Java动态代理,如何实现一个动态代理例子

更新时间:2023-05-13 02:14:34 阅读: 评论:0

什么是Java动态代理,如何实现⼀个动态代理例⼦
Java动态代理
⼀、概述
1. 什么是代理
我们⼤家都知道微商代理,简单地说就是代替⼚家卖商品,⼚家“委托”代理为其销售商品。关于微商代理,⾸先我们从他们那⾥买东西时通常不知道背后的⼚家究竟是谁,也就是说,“委托者”对我们来说是不可见的;其次,微商代理主要以朋友圈的⼈为⽬标客户,这就相当于为⼚家做了⼀次对客户群体的“过滤”。我们把微商代理和⼚家进⼀步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。通过使⽤代理,通常有两个优点,并且能够分别与我们提到的微商代理的两个特点对应起来:
优点⼀:可以隐藏委托类的实现;
优点⼆:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做⼀些额外的处理。
2. 静态代理
若代理类在程序运⾏前就已经存在,那么这种代理⽅式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同⼀接⼝或是派⽣⾃相同的⽗类。 下⾯我们⽤Vendor类代表⽣产⼚家,BusinessAgent类代表微商代理,来介绍下静态代理的简单实现,委托类和代理类都实现了Sell接⼝,Sell接⼝的定义如下:
水果创意拼盘/**
* 委托类和代理类都实现了Sell接⼝
*/
public interface Sell {
void ll();
void ad();
}
复制代码
Vendor类的定义如下:
/**
* ⽣产⼚家
*/
public class Vendor implements Sell {
public void ll() {
System.out.println("In ll method");
}
public void ad() {
System,out.println("ad method");
}
}
复制代码
代理类BusinessAgent的定义如下:才高八斗指的是谁
/**
* 代理类
*/
public class BusinessAgent implements Sell {
private Sell vendor;
辛丑条约内容public BusinessAgent(Sell vendor){
this.vendor = vendor;
婚前婚后
}
public void ll() {
vendor.ll();
}
public void ad() {
vendor.ad();
}
}
复制代码
从BusinessAgent类的定义我们可以了解到,静态代理可以通过聚合来实现,让代理类持有⼀个委托类的引⽤即可。
下⾯我们考虑⼀下这个需求:给Vendor类增加⼀个过滤功能,只卖货给⼤学⽣。通过静态代理,我们⽆需修改Vendor类的代码就可以实现,只需在BusinessAgent类中的ll⽅法中添加⼀个判断即可如下
所⽰:
/**
* 代理类
*/
public class BusinessAgent(){ implements Sell {
private Sell vendor;
public BusinessAgent(Sell vendor){
this.vendor = vendor;
}
public void ll() {
if (isCollegeStudent()) {
vendor.ll();
}
}
public void ad() {
vendor.ad();
}
}
复制代码
这对应着我们上⾯提到的使⽤代理的第⼆个优点:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做⼀些额外的处理。静态代理的局限在于运⾏前必须编写好代理类,下⾯我们重点来介绍下运⾏时⽣成代理类的动态代理⽅式。
⼆、动态代理
1. 什么是动态代理
代理类在程序运⾏时创建的代理⽅式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,⽽是在运⾏时根据我们在Java代码中的“指⽰”动态⽣成的。相⽐于静态代理, 动态代理的优势在于可以很⽅便的对代理类的函数进⾏统⼀的处理,⽽不⽤修改每个代理类的函数。 这么说⽐较抽象,下⾯我们结合⼀个实例来介绍⼀下动态代理的这个优势是怎么体现的。
现在,假设我们要实现这样⼀个需求:在执⾏委托类中的⽅法之前输出“before”,在执⾏完毕后输出“after”。我们还是以上⾯例⼦中的Vendor类作为委托类,BusinessAgent类作为代理类来进⾏介绍。⾸先我们来使⽤静态代理来实现这⼀需求,相关代码如下:
public class BusinessAgent implements Sell {
private Vendor mVendor;
public BusinessAgent(Vendor vendor) {
this.mVendor = vendor;
}
public void ll() {
古代小说推荐System.out.println("before");
mVendor.ll();
System.out.println("after");
}
public void ad() {
System.out.println("before");
mVendor.ad();
System.out.println("after");
}
}
复制代码
从以上代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个⽅法中都添加相应的逻辑,这⾥只存在两个⽅法所以⼯作量还不算⼤,假如Sell接⼝中包含上百个⽅法呢?这时候使⽤静态代理就会编写许多冗余代码。通过使⽤动态代理,我们可以做⼀个“统⼀指⽰”,从⽽对所有代理类的⽅法进⾏统⼀处理,⽽不⽤逐⼀修改每个⽅法。下⾯我们来具体介绍下如何使⽤动态代理⽅式实现我们的需求。
2. 使⽤动态代理
2.1 InvocationHandler接⼝
在使⽤动态代理时,我们需要定义⼀个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接⼝,这个接⼝的定义如下:
/**
* 调⽤处理程序
*/
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
复制代码
从InvocationHandler这个名称我们就可以知道,实现了这个接⼝的中介类⽤做“调⽤处理器”。当我们调⽤代理类对象的⽅法时,这
个“调⽤”会转送到invoke⽅法中,代理类对象作为proxy参数传⼊,参数method标识了我们具体调⽤的是代理类的哪个⽅法,args为这个⽅法的参数。这样⼀来,我们对代理类中的所有⽅法的调⽤都会变为对invoke的调⽤,这样我们可以在invoke⽅法中添加统⼀的处理逻辑(也可以根据method参数对不同的代理类⽅法做不同的处理)。因此我们只需在中介类的invoke⽅法实现中输出“before”,然后调⽤委托类的invoke⽅法,再输出“after”。下⾯我们来⼀步⼀步具体实现它。
2.2 委托类的定义
动态代理⽅式下,要求委托类必须实现某个接⼝,这⾥我们实现的是Sell接⼝。委托类Vendor类的定义如下:
public class Vendor implements Sell {
public void ll() {
System.out.println("In ll method");
}
public void ad() {
System,out.println("ad method");
}
公牛蚁}
万科王石复制代码
2.3中介类
上⾯我们提到过,中介类必须实现InvocationHandler接⼝,作为调⽤处理器”拦截“对代理类⽅法的调⽤。中介类的定义如下:
public class DynamicProxy implements InvocationHandler {
//obj为委托类对象;
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(obj, args);
System.out.println("after");
return result;
}
}
复制代码
从以上代码中我们可以看到,中介类持有⼀个委托类对象引⽤,在invoke⽅法中调⽤了委托类对象的相应⽅法,看到这⾥是不是觉得似曾相识?
通过聚合⽅式持有委托类对象引⽤,把外部对invoke的调⽤最终都转为对委托类对象的调⽤。这不就是我们上⾯介绍的静态代理的⼀种实现⽅式吗?
实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类;
代理类与中介类也构成⼀个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。
也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下⾯我们来介绍⼀下如何”指⽰“以动态⽣成代理类。
2.4动态⽣成代理类
动态⽣成代理类的相关代码如下:
public class Main {
public static void main(String[] args) {
//创建中介类实例
DynamicProxy inter = new DynamicProxy(new Vendor());
//加上这句将会产⽣⼀个$Proxy0.class⽂件,这个⽂件即为动态⽣成的代理类⽂件
//获取代理类实例ll
Sell ll = (Sell)(wProxyInstance(ClassLoader(), new Class[] {Sell.class}, inter));
//通过代理类对象调⽤代理类⽅法,实际上会转到invoke⽅法调⽤
ll.ll();
ll.ad();
}
}
复制代码
在以上代码中,我们调⽤Proxy类的newProxyInstance⽅法来获取⼀个代理类实例。这个代理类实现了我们指定的接⼝并且会把⽅法调⽤分发到指定的调⽤处理器。这个⽅法的声明如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
复制代码
⽅法的三个参数含义分别如下:
死胎有什么症状loader:定义了代理类的ClassLoder; interfaces:代理类实现的接⼝列表 h:调⽤处理器,也就是我
们上⾯定义的实现了InvocationHandler接⼝的类实例
我们运⾏⼀下,看看我们的动态代理是否能正常⼯作。我这⾥运⾏后的输出为
说明我们的动态代理确实奏效了。
上⾯我们已经简单提到过动态代理的原理,这⾥再简单的总结下:⾸先通过newProxyInstance⽅法获取代理类实例,⽽后我们便可以通过这个代理类实例调⽤代理类的⽅法,对代理类的⽅法的调⽤实际上都会调⽤中介类(调⽤处理器)的invoke⽅法,在invoke⽅法中我们调⽤委托类的相应⽅法,并且可以添加⾃⼰的处理逻辑。
三、代理模式
这个应该是设计模式中最简单的⼀个了,类图

本文发布于:2023-05-13 02:14:34,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/607492.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:代理   实现   委托   动态   静态   代码
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图