静态代理

编译阶段就生产了对应的代理类

public interface IBussiness {
void execute();
}
public class BussinessImpl implements IBussiness{
@Override
public void execute() {
System.out.println("执行业务逻辑...");
}
}
public class BussinessProxy implements IBussiness{

    private IBussiness bussinessImpl;

    public BussinessProxy(IBussiness bussinessImpl) {
this.bussinessImpl = bussinessImpl;
} @Override
public void execute() {
System.out.println("前拦截...");
bussinessImpl.execute();
System.out.println("后拦截...");
}
}
public class Test {

    public static void main(String[] args) {

        IBussiness bussiness = new BussinessImpl();
BussinessProxy proxy = new BussinessProxy(bussiness);
proxy.execute(); }
}

JDK动态代理

动态生成字节码,加载到内存中,利用反射去执行真正的方法

关键代码:

Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);

生成代理类时,要将类加载器,接口和InvocationHandler传递过去,

类加载器的作用是,生成的字节码要加载到JVM当中

接口的作用是,生成的代理类要知道代理的有哪些方法

InvocationHandler的作用是,在代理类中实际执行的是InvocationHandler的invoke方法

public interface Person {
/**
* 唱歌
*/
void sing();
/**
* 跳舞
* @param name 舞曲名
* @return
*/
String dance(String name);
}
public class PersonImpl implements Person{

    @Override
public void sing() {
System.out.println("开始唱歌");
} @Override
public String dance(String name) {
System.out.println("跳" + name);
return "不好玩";
}
}
public class PersonImplProxy {

    private Person person = new PersonImpl();

    /**
* 创建代理
* @return 返回值是接口类型
*/
public Person createProxy() {
/**
* 产生某个对象的代理对象
* ClassLoader loader 当前代理对象的类加载器
* Class<?>[] interfaces 代理对象的接口
* InvocationHandler h InvocationHandler对象
*/
return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() { /**
* @param proxy 把代理对象自身传进去
* @param method 代表当前调用的方法
* @param args 当前调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取方法名
String methodName = method.getName();
if ("sing".equals(methodName)) {
System.out.println();
System.out.println("前置通知... 唱歌开始");
method.invoke(person, args);
System.out.println("后置通知... 唱歌结束");
} else if ("dance".equals(methodName)) {
System.out.println();
System.out.println("前置通知 ... 跳舞开始");
Object res = method.invoke(person, args);
System.out.println("后置通知 ... 跳舞结束");
return res;
}
return null;
}
});
} }
public class Test {
public static void main(String[] args) {
//设置为true后,可以保存生成的代理类的字节码,
//注意字节码文件用jd-gui.exe打开,用javap打开显示不全,javap是JDK自带的工具,他们之间的具体实现是不一样的
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
PersonImplProxy proxy = new PersonImplProxy();
Person person = proxy.createProxy();
person.sing();
System.out.println(person.dance("华尔兹三章"));
System.out.println();
System.out.println("生成的代理类的名称: " + person.getClass().getName()); } }

测试结果

生成字节码文件

将字节码文件反编译后

public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
} public final boolean equals(Object paramObject) {
try {
return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final String toString() {
try {
return (String) this.h.invoke(this, m2, null);
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final void sing() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final String dance(String paramString) {
try {
return (String) this.h.invoke(this, m4, new Object[] { paramString });
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final int hashCode() {
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} 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[]);
m3 = Class.forName("com.irish.deligate.Person").getMethod("sing", new Class[]);
m4 = Class.forName("com.irish.deligate.Person").getMethod("dance",
new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[]);
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

可以看到代理类继承了Proxy,实现了我们传递的接口,当调用dance方法时,会转调InvocationHandler的invoke方法,将方法和参数传递过去,由invoke来具体执行代理的逻辑,InvocationHandler持有真正的对象,一般是在调用真正的对象方法前后,执行我们要进行增强的操作。

java静态代理和JDK动态代理的更多相关文章

  1. java代理(静态代理和jdk动态代理以及cglib代理)

    版权声明:本文为Fighter168原创文章,未经允许不得转载.   目录(?)[+]   说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等. 记忆特别深刻 ...

  2. 静态代理和jdk动态代理

    要说动态代理,必须先聊聊静态代理. 静态代理 假设现在项目经理有一个需求:在项目现有所有类的方法前后打印日志. 你如何在不修改已有代码的前提下,完成这个需求? 我首先想到的是静态代理.具体做法是: 1 ...

  3. AOP的底层实现-CGLIB动态代理和JDK动态代理

    AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...

  4. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

  5. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  6. 代理模式之静态代理,JDK动态代理和cglib动态代理

    代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ...

  7. jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

    代理模式是一种很常见的模式,本文主要分析cglib动态代理的过程 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.c ...

  8. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  9. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

随机推荐

  1. maven install

    1. install maven under ubuntu apt install maven 2 speed up package download vim ~/.m2/settings.xml & ...

  2. 平安银行Java面试-社招-五面(2019/09)

    个人情况 2017年毕业,普通本科,计算机科学与技术专业,毕业后在一个二三线小城市从事Java开发,2年Java开发经验.做过分布式开发,没有高并发的处理经验,平时做To G的项目居多.写下面经是希望 ...

  3. 【POJ2251】Dungeon Master

    本题传送门 本题知识点:宽度优先搜索 题意简单.在一个L层高的楼里,去走迷宫,就是问从S走到E的最短路径.每走一格每上或者下一层都算1步. 一开始以为这个"立体迷宫"有点吓到我(题 ...

  4. 第2课第5节_Java面向对象编程_异常_P【学习笔记】

    摘要:韦东山android视频学习笔记  java的异常处理的原则如下: 1.我们先写一个没有对异常处理的程序,在进行除法运算的时候,除数是非零的话,运行时没有问题的,但是除数为零的时候,运行就会有问 ...

  5. jmeter测试 flask 接口请求

    jmeter测试 flask 接口请求 flask的代码如下: #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flas ...

  6. PostMan Request Export

  7. 一款阿里开源的 Java 诊断工具

    Arthas是什么鬼? Arthas是一款阿里巴巴开源的 Java 线上诊断工具,功能非常强大,可以解决很多线上不方便解决的问题. Arthas诊断使用的是命令行交互模式,支持JDK6+,Linux. ...

  8. LC 968. Binary Tree Cameras

    Given a binary tree, we install cameras on the nodes of the tree. Each camera at a node can monitor  ...

  9. springboot 整合Elasticsearch

    Elasticsearch Elasticsearch 是一个分布式.可扩展.实时的搜索与数据分析引擎. 它能从项目一开始就赋予你的数据以搜索.分析和探索的能力,可用于实现全文搜索和实时数据统计. 在 ...

  10. Spring MVC -- Spring MVC入门

    本篇博客首先介绍Spring MVC的优点,然后介绍Spring MVC的基本组件,包括DispatcherServlet,并学习如何开发一个“传统风格”的控制器,这是在Spring 2.5版本之前开 ...