静态代理

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

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. L1434滑雪

    一,看题 1,这个长度怎么算的. 从它自己数,可以走下去的位置. 2,这个题的衣服怎么披上去呀. 3,搜索目标,状态. 肯定要用坐标,不然怎么搜索. 4,在前期还是多写把. 5,我靠这个点还是随机的& ...

  2. 2019.12.11 java方法(类似功能、函数)

    方法的具体语法格式如下: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,......){     执行语句     ………     return 返回值; }   class D ...

  3. 【批处理】choice命令,call 命令,start 命令,rem

    [1]choice命令简介 使用此命令可以提示用户输入一个选择项,根据用户输入的选择项再决定执行具体的过程. 使用时应该加/c:参数,c: 后应写提示可输入的字符或数字,之间无空格.冒号是可选项. 使 ...

  4. ELK教程3:logstash的部署、SpringBoot整合ELK+Filebeat

    本篇文章主要讲解如下安装Logstash,logstash依赖于Java环境,首先安装Java,安装脚本如下: yum install java logstash安装 Logstash的安装脚本如下: ...

  5. 原创:协同过滤之ALS

    推荐系统的算法,在上个世纪90年代成型,最早应用于UserCF,基于用户的协同过滤算法,标志着推荐系统的形成.首先,要明白以下几个理论:①长尾理论②评判推荐系统的指标.之所以需要推荐系统,是要挖掘冷门 ...

  6. 原创:自定义spark GraphX中的collectNeighborIds方法

    /** * 自定义收集VertexId的neighborIds * @author TongXueQiang */def collectNeighborIds[T,U](edgeDirection:E ...

  7. Codeforces Round #595 (Div. 3)

    A - Yet Another Dividing into Teams 题意:n个不同数,分尽可能少的组,要求组内没有两个人的差恰为1. 题解:奇偶分组. int a[200005]; void te ...

  8. OpenFOAM——运动和静止的同心圆柱之间的流动(库埃特流)

    本算例来自<ANSYS Fluid Dynamics Verification Manual>中的VMFL001: Flow Between Rotating and Stationary ...

  9. JAVA学习网站分享

    好久没用博客园了 最近工作不忙了,可以花时间自己学习知识提升自己,所以开始查找各种资料 java资源查找网站:           http://www.java1234.com/ 前端学习网站:  ...

  10. jmeter BeanShell断言(四)

    Bean Shell常用内置变量 JMeter在它的BeanShell中内置了变量,用户可以通过这些变量与JMeter进行交互,其中主要的变量及其使用方法如下: log:写入信息到jmeber.log ...