当前位置:首页 > CN2资讯 > 正文内容

(超详细!)彻底搞懂动态代理和静态代理动态代理和静态代理

12小时前CN2资讯



文章目录


  • ​​什么是静态代理(Static Proxy)​​
  • ​​静态代理的缺点​​
  • ​​什么是动态代理​​
  • ​​总结​​


想要明白什么是动态代理,那么就一定要知道什么是动态代理,动态代理有啥用,为什么需要动态代理,是因为出现了什么问题,所以产生了动态代理这门技术。所以在谈动态代理之前,我们先来看看什么是静态代理:

什么是静态代理(Static Proxy)

什么是代理?代理就是给目标类提供一个代理对象,由代理对象控制目标对象的引用。

代理有啥好处呢?①通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性,②通过代理对象对原有的业务增强。

如果代理不重要,老板为啥会一人整一个秘书呢?因为秘书可以代替老板做很多不必要老板亲自出场的工作。或者有人想见老板(真正的对象),则需要先访问秘书(代理对象),秘书同意之后才能见面。

假如小李是一个江南皮革厂的老板,但是在创业初期,他没有足够的前,所以只能先低价购入韩国皮鞋,然后有小张觉得小李的鞋不错,而且便宜,所以就一直让小李代购。

他们的UML图如下:

先看一个例子:

tip:为了通俗所以使用了汉字,实际开发切忌不可使用汉字

先看抽象接口:

package com.bean.pixie;

//抽象接口:描述了服务提供者的行为
public interface 理宁 {
void saleShoes(String size);//尺码
}

然后是真实的对象:

package com.bean.pixie;

//代理对象
public class 小李 implements 卖鞋{

//被包含的真实对象
private 理宁 lining;

public 小李(理宁 lining) {
this.lining = lining;
}

@Override
public void saleShoes(String size) {
doSomethingBefore();
lining.saleShoes(size);
doSomethingAfter();
}

//前置增强
private void doSomethingBefore() {
System.out.println("检查鞋子是不是ok");
}

//后置增强
private void doSomethingAfter() {
System.out.println("将鞋子发送给客户");
}
}

由于小李(代理对象)并非是真实生产鞋子的,所以它包含一个真实对象做实际的工作,但是小李存在的意义是在真实对象做实际工作前后去做一些其他的方法。

看看客户小张的代码:

//客户小张>>
public class 小张 {
public static void main(String[] args) {
卖鞋 shoe = new 理宁();
小李 li = new 小李((理宁) shoe);
li.saleShoes("42");
}
}

看一下打印结果:

这就是静态代理的流程。

静态代理的缺点

假设小李的业务越做越好,越做越大,然后又有很多新的客户,并且客户有很多新的需求,比如有的要日本鞋,有的要欧美鞋。这个整体结构就变了。

需要新建新的抽象类、新的公司、新的用户,如果需求不断在增加,则代理对象会不停的实现接口,写新方法,代码就会非常非常冗余,非常多,这就造成了严重的耦合问题

这就违反了设计模式七大原则之一:开闭原则(ocp),所谓ocp原则就是对程序扩展是open的,但是对于源码修改是close的,显然静态代理必须要修改源码。另外当前这个例子,还应该遵循单一原则:一个类或者一个接口只负责一个任务,尽量设计出职责单一的接口。依赖倒转原则:高层模块不应该依赖底层模块,解耦高层与底层,既然是面向接口编程,当实现发生变化时,只需提供新的实现类,不需要修改高层模块代码。

什么是动态代理

后来小李有钱了,开了个代购公司,公司有很多员工,有的员工很了解日本的鞋,有的很了解韩国货,有的很了解欧美货等等,当客户来买鞋的时候,小李只需要动态的挑选了解对方需求的员工然后去让他们负责就行了,这就体现了动态性。

假设小李又和一家新公司按踏进行了合作,按踏专门卖洋鞋的,所以产生了一个抽象接口:卖洋鞋:

package com.bean.pixie;

public interface 卖洋鞋 {
void saleForeignShows(int size);
}

按踏是专门卖洋鞋的,所以他需要实现这个接口:

package com.bean.pixie;

public class 按踏 implements 卖洋鞋{

@Override
public void saleForeignShows(int size) {
System.out.println("洋鞋尺寸为"+size+"码");
}
}

看看小李代购工厂的代码:

package com.bean.pixieCompany;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class 小李代购公司 implements InvocationHandler {

//被代理的对象
private Object 鞋厂;

public void set鞋厂(Object 鞋厂) {
this.鞋厂 = 鞋厂;
}

//通过动态代理对方法进行增强
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomethingBefore();
Object invoke = method.invoke(鞋厂, args);
doSomethingAfter();
return invoke;
}

//通过Proxy获得动态代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(鞋厂.getClass().getClassLoader(),鞋厂.getClass().getInterfaces(),this);
}

//前置增强
private void doSomethingBefore() {
System.out.println("检查鞋子是不是ok");
}

//后置增强
private void doSomethingAfter() {
System.out.println("将鞋子发送给客户");
}
}

此时我们新建一个测试类,里面有两种用户,有不同需求:

package com.bean.pixieCompany;

import com.bean.pixie.卖洋鞋;
import com.bean.pixie.卖鞋;
import com.bean.pixie.按踏;
import com.bean.pixie.理宁;

public class 客户 {
public static void main(String[] args) {
//1.卖洋鞋的工作由按踏公司生产
卖洋鞋 fshoe = new 按踏();
//2.卖普通鞋工作由理宁公司生产
卖鞋 sshoe = new 理宁();
//3.小李成立的代购公司
小李代购公司 liCom = new 小李代购公司();
//4.小刘来买洋鞋,则需要将卖洋鞋的工厂传给小刘代购公司
liCom.set鞋厂(fshoe);
//5.一号员工对卖洋鞋很有一套,交由一号员工处理
卖洋鞋 No_1 = (卖洋鞋)liCom.getProxyInstance();
//6.一号员工为小刘服务,完成代购
No_1.saleForeignShows(39);
System.out.println("==================");
//7.想买普通鞋的小赵来买鞋,则需要传入理宁代购公司对象
liCom.set鞋厂(sshoe);
//8.委派适合卖普通鞋的二号员工
卖鞋 No_2 = (卖鞋)liCom.getProxyInstance();
No_2.saleShoes("42");
}
}

想了解动态代理,反射原理必须清楚,想了解反射的童鞋可以参考一下我的上篇博客:​​javascript:void(0)​​

我在这里简单介绍一下这个动态代理的原理:

由于小李代购公司有一个真实代理对象是Object类型的,所以可以接受任何类型的鞋厂,由于有不同的需求,所以设置不同的公司给鞋厂对象,设值后,小李代购公司这个类的工厂就有对象了,我想做的下一步是要调用当前这个工厂的卖鞋方法,所以接下来就是通过反射获得代理实例的过程,需要调用自己写的getProxyInstance这个方法,可以看出方法的返回值是Proxy.newInstance(ClassLoader c,Class<?>[] Interfaces,InvocationHandler);根据类加载器可以确定要把哪个类加载到内存,给了接口,可以确定这个类实现了哪些接口,最后一个InvocationHandler就是实际去调用代理对象方法的一个接口,什么意思呢,就是通过InvocationHandler接口中的唯一方法invoke,去调用你想使用的方法,通过getProxyInstance方法获得了一个代理对象,他是你想要的类型,由于InvocationHandler的缘故,所以该代理对象会调用当前InvocationHandler的invoke方法,执行前后增强的操作,并且返回最终的代理对象,拿到了最终的代理对象之后,就可以随意调用它的方法了。

直接说不容易理解,我们来看一下流程图:

这是小李代购公司代购的流程图,再看反射的流程图,为啥可以拿到理宁或者按踏类:

总结

通过动态代理,可以减少程序的耦合度,分工明确,但是反射等知识有点不好理解,需要童鞋深入研究一下~~~


    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/24685.html

    分享给朋友:

    “(超详细!)彻底搞懂动态代理和静态代理动态代理和静态代理” 的相关文章

    WordPress登录验证设置:提升网站安全性与用户体验

    在使用WordPress构建网站时,登录验证设置是确保用户身份安全和信息保护的重要环节。它不仅涉及用户从何处进入网站,更关乎整个网站的安全性能。在这章中,我将为你详细解析什么是WordPress登录验证,它的重要性以及基本的流程。 什么是WordPress登录验证 WordPress登录验证主要是通...

    APT攻击是什么及其防御措施详解

    APT攻击(Advanced Persistent Threat,高级持续性威胁)是一种复杂而长期的网络攻击模式。在我了解这个概念的过程中,逐渐意识到它不仅仅是一种攻击手段,而是一个精密的、组织化的网络战争策略。APT攻击的敌对方通常具备高超的技术能力和丰富的资源,他们的目标是破坏组织的核心设施,或...

    AkkoCloud评测:为中国用户打造的高性价比VPS与独立服务器解决方案

    AkkoCloud成立于2019年,作为一家具备国人运营背景的主机商,逐渐在海内外VPS和独立服务器市场中占据了一席之地。我的亲身体验让我感受到,AkkoCloud的设计初衷就是为中国大陆的用户提供一个稳健可靠的服务器解决方案。对于很多用户来说,它的出现无疑填补了国内市场的一部分空白。 回想起我探索...

    如何有效使用WP Rocket插件提升WordPress网站性能

    WP Rocket是一个强大的高级WordPress缓存插件,它的使用对于提升网站的速度和性能起着至关重要的作用。如今,网站的加载速度对于用户体验和SEO排名都有着重要的影响。WP Rocket通过一系列功能和设置,帮助用户轻松优化自己的网站,进而增加访问量和客户满意度。 在使用WP Rocket插...

    最优秀的IP检测工具,提升网络安全与性能的选择

    IP检测工具是一种极为重要的网络资源,旨在帮助用户识别和分析IP地址信息。像我们在日常上网时,需要了解自己的网络状态,了解与其他用户的连接关系,这时候IP检测工具就显得尤为重要。无论你是网络管理员、开发者,还是只是单纯的网络用户,这类工具总是能够给你带来实用的信息与帮助。 了解IP检测工具的工作原理...

    选择最佳VPS主机服务:Digital-VM全面解析与性能优化策略

    谈到 Digital-VM,我总会被它的成长故事所吸引。这家主机商成立于2018年,致力于为用户提供高效、灵活的VPS主机解决方案。作为一家美国公司,它在短时间内就扩大了服务范围,减少了用户在选择主机服务时的焦虑。Digital-VM 看似是一颗新星,却在竞争激烈的市场中脱颖而出,令人刮目相看。 在...