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

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

静态代理

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

接口类(被代理):

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静态方法,传入对应得参数即可得到需要的代理类,再将其强转赋值给需要的接口,即可正常使用。

Java代理笔记的更多相关文章

  1. Java学习笔记——动态代理

    所谓动态,也就是说这个东西是可变的,或者说不是一生下来就有的.提到动态就不得不说静态,静态代理,个人觉得是指一个代理在程序中是事先写好的,不能变的,就像上一篇"Java学习笔记——RMI&q ...

  2. java学习笔记13--反射机制与动态代理

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...

  3. 瘋耔java语言笔记

    一◐ java概述                                                                                        1.1 ...

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

    目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...

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

    目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个 ...

  6. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

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

    Java系列笔记(1) - Java 类加载与初始化 原文地址:http://www.cnblogs.com/zhguang/p/3154584.html 目录 类加载器 动态加载 链接 初始化 示例 ...

  8. JAVA自学笔记27

    JAVA自学笔记27 1.类的加载 1)当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. ①加载:就是指将class文件读入内存,并为之创 ...

  9. head first java读书笔记

    head first java读书笔记 1. 基本信息 页数:689 阅读起止日期:20170104-20170215 2. 标签 Java入门 3. 价值 8分 4. 主题 使用面向对象的思路介绍J ...

随机推荐

  1. NLP(二十五)实现ALBERT+Bi-LSTM+CRF模型

      在文章NLP(二十四)利用ALBERT实现命名实体识别中,笔者介绍了ALBERT+Bi-LSTM模型在命名实体识别方面的应用.   在本文中,笔者将介绍如何实现ALBERT+Bi-LSTM+CRF ...

  2. selenium+chromdriver 动态网页的爬虫

    # 获取加载更多的数据有 2 种方法# 第一种就是直接找数据接口, 点击'加载更多' 在Network看下, 直接找到数据接口 # 第二种方法就是使用selenium+chromdriver # se ...

  3. django中ORM中锁和事务

    一 锁 行级锁 select_for_update(nowait=False, skip_locked=False) #注意必须用在事务里面,至于如何开启事务,我们看下面的事务一节. 返回一个锁住行直 ...

  4. 提示消息无缝向上滚动(vue)

    <div class="order-tips__message-item" :class="getClass(index)" v-for="(o ...

  5. 一口气说出 6种,@Transactional注解的失效场景

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一口气说出 9种 分布式ID生成方式,面试官有点懵了 面试总被问 ...

  6. sql优化,如何将in换为exists

    原sql语句 -- 根据权限表查出该用户拥有的所有权限菜单 select * from tb_power where id in( select power_id from tb_role_power ...

  7. SpringCloud学习系列<一>版本介绍

    SpringCloud学习踩坑记<一> SpringCloud版本迭代实在太快,学习起来也是各种坑,博主用的是"当前"的最新版本,借鉴周立老大的Spring Cloud ...

  8. 基于 HTML5 Canvas 的拓扑组件 ToolTip 应用

    前言 ToolTip 效果是网页制作中常见的使用特效.当用户将鼠标悬浮在某个控件上时,ToolTip 显示并向用户展示相应的提示信息:当鼠标离开时,ToolTip 隐藏.一般情况下,我们使用 Tool ...

  9. 测试工程师需要了解的shell变量知识

    欢迎访问个人博客 什么是变量 本地变量:手动定义的,在当前系统的某个环境下才能生效,作用范围小 普通变量: 单引号:原字符输出,变量名='变量值' ➜ shell name='tom' ➜ shell ...

  10. RabbitMQ 在Ubuntu18.04上的安装

    1.安装erlang由于rabbitMq需要erlang语言的支持,在安装rabbitMq之前需要安装erlang sudo apt-get install erlang2.安装Rabbitmq更新源 ...