Java代理笔记

代理顾名思义,就是一个中间层,当我们要使用某个方法时,不直接调用,而是告诉代理,让代理替我们去请求方法,并返回结果。在这个过程中,我们只知道代理执行并返回给了我们操作结果,至于它有没有其他操作并不知道,但这个也无关紧要,因为不管代理在请求实际方法之前和之后做了什么,对我们都不会产生任何影响。由于代理的这个特性,可以用来进行记录日志等操作。

代理分为静态代理动态代理

静态代理

静态代理需要我们在调用者和具体的执行者之间创建一个代理类,其实现需要被代理的接口并持有一个此接口,具体代码如下:

接口类(被代理):

public interface Hello {
    void say(String name);
}

代理类:

public class HelloProxy implements Hello {
?
    private Hello helloImpl;
?
    public HelloProxy() {
        this.helloImpl = new HelloImpl(); // HelloImpl为一个Hello接口的一个普通实现类
    }
?
    @Override
    public void say(String name) {
        System.out.println("before say");
        helloImpl.say(name);
        System.out.println("after say");
    }
}

使用的时候只需要new一个代理类赋值给接口即可:Hello hello = new HelloProxy(),之后的执行会由代理类去负责。但是这么做有一个问题就是对每个需要代理的类,都需要创建一个对应的代理类,即使代理类的逻辑都是相似的,动态代理就是解决这个问题的。

动态代理

动态代理相当于在调用者和代理类之间又增加了一个中间层,在这个中间层中完成代理类的逻辑,达到复用代码的效果。这个中间层需要实现InvocationHandler接口,并持有一个被代理的类,大致代码如下:

public class Myproxy implements InvocationHandler {
?
    private Object target; // 被代理的类
?
    public Myproxy(Object target) {
        this.target = target;
    }
?
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke"); // 执行代理的方法前进行的操作
        Object invoke = method.invoke(target, args); // 调用执行被代理的方法
        System.out.println("after invoke"); // 执行代理的方法后进行的操作
        return invoke; // 返回方法执行结果
    }
}

使用时,使用Proxy的静态方法获取代理类,将其强转为对应的接口,之后可以同静态代理类同样使用。

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

其中loader为类加载器,interfaces为要代理的接口,h为之前定义的实现InvocationHandler接口的类的实例。

这个方法会返回一个代理类,其实现的要代理的接口,并持有一个实现InvocationHandler接口的实例,代理类的代码大致如下:

public final class $Proxy0 extends Proxy
  implements Hello
{
?
  public $Proxy0(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }
?
  public final String say() {
    try
    {
      return ((String)this.h.invoke(this, m3, null));
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
?
}

如上代码我们可以将其强转为Hello接口,实际调用的时候会调用InvocationHandler实现类中的invoke方法,而其中就是我们实现的代理业务,当然,也包括实际的业务。

这样,对于有相同代理业务的类,我们只要实现InvocationHandler接口,在其中的invoke方法实现需要代理的业务,使用时只要使用Proxy.newProxyInstance静态方法,传入对应得参数即可得到需要的代理类,再将其强转赋值给需要的接口,即可正常使用。

时间: 2024-11-01 14:49:57

Java代理笔记的相关文章

java学习笔记14--动态代理

java学习笔记14--动态代理 InvocationHandler接口 [java] view plaincopy public interface InvocationHandler{ public Object invoke(Object proxy,Method method,Object[] args)throws Throwable } 参数说明: Object  proxy:被代理的对象 Method  method:要调用的方法 Object   args[]:方法调用时所需要的

Java学习笔记——动态代理

所谓动态,也就是说这个东西是可变的,或者说不是一生下来就有的.提到动态就不得不说静态,静态代理,个人觉得是指一个代理在程序中是事先写好的,不能变的,就像上一篇"Java学习笔记--RMI"中的远程代理,其中客户端服务对象就是一个远程服务对象的代理,这个代理可以使得客户在操作时感觉像在操作本地对象一样,远程对象对于客户是透明的.我们可以看出这里的远程代理,是在程序中事先写好的,而本节我们要讨论的远程代理,是由JVM根据反射机制,在程序运行时动态生成的.(以上是本人的理解,如果有不正确的地

Java系列笔记(1) - Java 类加载与初始化

目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一个原生的类加载器,它只加载Java API等可信类,通常只是在本地磁盘中加载,这些类一般就够我们使用了.如果我们需要从远

Java系列笔记(2) - Java RTTI和反射机制

目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这就是RTTI(Runtime Type Information,运行时类型信息). 在java中,有两种RTTI的方式,一种是传统的,即假设在编译时已经知道了所有的类型:还有一种,是利用反射机制,在运行时再尝试确定类型信息. 本文主要讲反射方式实现的RTTI,建议在阅读本文之前,先了解类的加载机制(

java学习笔记14--多线程编程基础1

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为一个进程,例如:用字处理软件编辑文稿时,同时打开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程 进程要占用相当一部分处理器时间和内存资源 进程具有独立的内存空间 通信很不方便,编程模型比较复杂 多线程 一个程序中多段代码同时并发执行,称为多线程,线程比进程开销小,协作和数据交换容易

【转载】Java系列笔记(1) - Java 类加载与初始化

Java系列笔记(1) - Java 类加载与初始化 原文地址:http://www.cnblogs.com/zhguang/p/3154584.html 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一

java学习笔记16--I/O流和文件

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note16.html,转载请注明源地址. IO(Input  Output)流 IO流用来处理设备之间的数据传输,对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中 输入/输出流可以从以下几个方面进行分类 从流的方向划分: 输入流.输出流 从流的分工划分: 节点流.处理流 从流的内容划分: 面向字符的流.面向字节的流 字符流和字节流 字符流的由来: 因为数据编码的不同,而有了对

Java代理Internet

Java代理Internet 2013年10月23日 23:14 Java HTTP Proxy Settings OVERVIEW For local networks within an organization, access to the public-domain Internet is often via a HTTP Proxy. This article talks about the HTTP proxy settings for the Java environment. I

Java学习笔记3-操作符

Java基本操作符:+.-.*./.%.=.==.!=.+=.-=. 优先级:先乘除后加减,如果是连接符+号会优先往前匹配,比如 a+++++b,会被解释称 a++ ++ +b,所以会报错,需要自行使用括号隔离为 (a++) + (++b). 对象的引用如果赋值给了对象的引用后,2 个对象将指向同一个引用,有一个对象的引用重新赋值后将同时影响到另一个对象,比如 ClassName classA = new ClassName(); ClassName classB = new ClassName