Java中的代理

Posted 飞蛾扑火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的代理相关的知识,希望对你有一定的参考价值。

 代理模式

 在设计模式中存在的代理模式;代理模式的作用就是为其他对象提供一种代理以控制对这个对象的访问。

 代理模式一般存在三种角色:抽象角色,代理角色,真实角色;百度百科上摘抄了三种角色的解释:

  抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
  代理模式的优点:一是可以隐藏委托类(真实角色)的实现,二是可以实现客户和委托类之间的解耦;

 Java中的代理

   在java中代理分静态代理和动态代理;所谓静态代理是在程序运行前代理类就已经存在的,一般这种代理类都是通过我们自己定义的java类来实现;动态代理相对就麻烦一些,是在程序运行时生成代理类;是通过我们在Java代码来动态生成的;

   现在有个场景:火车站售票,有些代理点也可以买票,在这里火车票代理点就是代理角色;

    首先把卖票抽象成一个接口: 

public interface iTicketService {

    void SellTicket(String name);
}

 

火车站卖票实现这个接口:

public class trainStation implements iTicketService {
    public void SellTicket(String name) {
        System.out.println(name + "成功购买了一张票");
    }
}

静态代理

 

  静态代理就是在java代码中我们自己定义代理类;代理类中持有委托类的引用;并且代理类也实现了和委托类一样的接口;

public class stationProxy implements iTicketService {
    private iTicketService TicketService;

    public stationProxy(iTicketService ticketService) {
        this.TicketService = ticketService;
    }

    public void SellTicket(String name) {
        System.out.println("代售点开始卖票");
        this.TicketService.SellTicket(name);
        System.out.println("代售点卖票成功");
    }
}

从代码中我们可以看到代理的好处,代理内部还是调用委托类的方法,我们在调用委托类的方法前或是方法后可以来进行一些相关操作;

静态代理的调用也非常的简单:

iTicketService ticketService=new trainStation();
stationProxy station=new stationProxy(ticketService);
station.SellTicket("张三");

输出:

代售点开始卖票

张三成功购买了一张票

代售点卖票成功

动态代理

 动态代理相对于静态代理的区别就在于代理类是在运行时生成的;动态代理的优势就在于可以方便的对代理类的函数统一的管理,而不用一个个的去修改代理函数,当代理非常多的时候,动态代理的优势就很多大了;

 InvocationHandler

在使用动态代理时,需要我们定义一个代理类和委托类之间关联的中介类,在java中这个中介类应该实现InvocationHandler接口;
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

在InvocationHandler接口中只有一个invoke方法,当代理类执行代理方法都会通过invoke方法来执行;proxy:代理类对象,method 需要执行的代理方法;args代理方法执行的参数,方法的返回值object也就是代理方法的返回值,我们可以在invoke方法内添加统一的处理逻辑;比如火车票代售点我们可以创建动态的代理类:

public class dynamicProxy implements InvocationHandler {
    private  iTicketService TicketService;
    public dynamicProxy(iTicketService ticketService){
        this.TicketService=ticketService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理开始卖票");
        Object obj= method.invoke(TicketService,args);
        System.out.println("动态代理卖票结束");
        return  obj;
    }
}

从dynamicProxy类来看,我们的代理类也持有委托类的一个实例,在 invoke中采用反射进行方法的执行;

在JAVA中实现了InvocationHandler接口的动态代理类需要借助Proxy获取实例

  dynamicProxy dynamicProxy=new dynamicProxy(ticketService);
   Class<?>[] interfaces=new  Class<?>[]{iTicketService.class};
   System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
   iTicketService ticketproxy=(iTicketService)Proxy.newProxyInstance(iTicketService.class.getClassLoader(),interfaces,dynamicProxy);
   ticketproxy.SellTicket("李四");

在Proxy类中通过newProxyInstance来获取代理类的实例;

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)

在newProxyInstance方法中ClassLoader是代理加载类,interfacess数组是类实现的接口数组,h就是我们自己定义的中介类了

通过System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");方法会产生一个$Proxy0.class文件,这个文件即为动态生成的代理类文件;

我们可以看下生成的代理类:

技术分享
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements iTicketService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void SellTicket(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("iTicketService").getMethod("SellTicket", new Class[]{Class.forName("java.lang.String")});
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
View Code

在生成的代理类中m3就是我们的接口定义的SellTicket方法,内部还是调用了InvocationHandler接口中的invoke方法;

 

 

以上是关于Java中的代理的主要内容,如果未能解决你的问题,请参考以下文章

(转) Java中的负数及基本类型的转型详解

Forge Viewer - 如何在场景中访问(或获取渲染/片段代理)克隆的网格?

java中的静态代理

java中的动态代理

有没有办法关闭代码片段中的命名建议?

java中的动态代理