java中的代理和动态代理讲解

xiaoxiao2021-02-28  97

在说到动态代理模式,我们首先说一说什么是代理模式。

 

什么是代理模式:

Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一

代理模式的定义:这里先举一个例子,假设某人要找对象,但是由于某些原因不能直接去找,于是委托一个中介机构去完成这一过程,如婚姻介绍所,在这里婚姻介绍所其实就是一个代理。再举一个专业相关的例子,如果你想调用一个功能非常强大的加密算法,而现在正在开发的系统又需要使用到该算法,由于该算法位于远程服务器端,封装该算法的对象位于远程服务器内存中,本地内存中的对象无法直接访问,因此需要通过一个远程代理的机制来实现远程对象的操作。也其实也就是webservice、httpclient等实现原理。再看代理的定义:给某一个对象提供一个代理,并有代理对象控制对原对象的引用。

优点:

职责清晰 :真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。增强代码的拓展性

结构

一个是真正的你要访问的对象(目标类),另一个是代理对象,真正对象与代理对象实现同一个接口。先访问代理类并通过代理对象来访问真正要访问的对象中的方法。

 

简单案例

在一个论坛中已注册用户和游客的权限不同个,已注册的用户拥有发帖、修改自己的注册信息、修改自己的帖子等功能;而游客只能看到别人发的帖子,没有其他权限。在这里我们使用代理模式来设计权限管理模块。

抽象主题类

public interface AbstractDemo { public void function(); }

AbstractDemo作为抽象权限类,充当了抽象主体角色,在其中声明了真实主题角色所提供的业务方法,它是真是主题角色和代理主题角色的公共接口。这里所说的主题角色就是需要被代理的对象

真实主题类(需要被代理的类)

public class RealDemo implements AbstractDemo { @Override public void function() { System.out.println("一种算法"); }

RealDemo是真实主题角色,它实现了在抽象主题角色中定义的方法,假设由于种种原因,客户端无法直接访问其中的方法。

代理主题角色

public class DemoProxy implements AbstractDemo { private RealDemo demo = new RealDemo(); @Override public void function() { demo.function(); } }

这样我们就用DemoProxy代理了RealDemo,并使用了RealDemo的function方法。

客户端调用 

public static void main(String[] args) { AbstractDemo demo = new DemoProxy(); demo.function(); }

 

动态代理模式

在上述的代理模式不知道大家有没有注意到一些问题,1、就是如果DemoProxy要想调用RealDemo中的function方法,首先这个真实主题角色也就是RealDemo必须存在。2、如果一个真实角色对应一个代理主题角色,这将导致系统中类的数量急剧增加。上述两个问题都是动态代理需要解决的问题。

接下来我们重复代理模式的过程,看看动态代理是怎样解决的

抽象主题类

package demo; public interface AbstractDemo { public void function(int i); }

真实主题类一(需要被代理的类)

public class RealDemo1 implements AbstractDemo { @Override public void function(int i) { System.out.println("一种加密算法"+i); } }

真实主题类二(需要被代理的类)

public class RealDemo2 implements AbstractDemo { @Override public void function(int i) { System.out.println("一种解密算法"+i); } }

动态代理的实现过程

class TestDemo { public static void main(String[] args) { final AbstractDemo demo1 = new RealDemo1(); // Proxy.newProxyInstance():产生代理类的实例。仅能代理实现至少一个接口的类 // ClassLoader:类加载器。也可以写成demo.getClass().getClassLoader()。 // Class[] interface:代理类要实现的接口。固定写法,和被代理类使用相同的接口即可。 // InvocationHandler:策略(方案)设计模式的应用。如何代理? AbstractDemo proxy = (AbstractDemo)Proxy.newProxyInstance(AbstractDemo.class.getClassLoader(), new Class[]{AbstractDemo.class}, new InvocationHandler() { // InvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行 // Object proxy:代理对象本身的引用。一般用不着。 // Method method:当前调用的方法。 // Object[] args:当前方法用到的参数 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行方法前"); Object obj = method.invoke(demo1,new Object[]{(int)args[0]}); System.out.println("执行方法后"); return obj; } }); proxy.function(2); } }

结果如下:

执行方法前 一种算法2 执行方法后

上面代码的注解非常详细,如果大家认真阅读,应该对动态代理应该明白的差不多了。阅读上面代码,动态代理可以动态地代理你说需要代理的对象,这里我们代理的是RealDemo1对象。如果我们想代理RealDemo2对象,那么我们只要首先实例RealDemo2对象,得到demo2,然后method.invoke(demo1,new Object[]{args[0]});中的demo1改成demo2即可。这样这个动态代理就可以代理很多主题类,那么系统的类就不会急剧增加了。

转载请注明原文地址: https://www.6miu.com/read-59510.html

最新回复(0)