静态代理

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

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. selenium模块及类组织关系

    问题:webdriver子模块中为什么可以直接使用类Chrome.ChromeOptions.Firefox.FirefoxProfile... 在webdriver的__init__.py文件中已经 ...

  2. go 学习 (三):函数 & 指针 & 结构体

    一.函数 函数声明 // 声明语法 func funcName (paramName paramType, ...) (returnType, returnType...) { // do somet ...

  3. [NPM + React] Prepare a Custom React Hook to be Published as an npm Package

    Before we publish our package, we want to make sure everything is set up correctly. We’ll cover vers ...

  4. 洛谷 P2983 [USACO10FEB]购买巧克力Chocolate Buying 题解

    P2983 [USACO10FEB]购买巧克力Chocolate Buying 题目描述 Bessie and the herd love chocolate so Farmer John is bu ...

  5. HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

    好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Ot ...

  6. 多项式乘法,sb题

    给定一个n,输出\((a1+x)*(a2+x)*...(an+x)\)的多项式长度. 每一个字符(包括"a"."x"."(".") ...

  7. vsftp 匿名访问设置设置

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/vsftpd_configuration vsftpd (very ...

  8. (转载)OpenStack client 调用分析

    https://blog.csdn.net/yenai2008/article/details/72722038?utm_source=itdadao&utm_medium=referral# ...

  9. (转载)基于Linux C的socket抓包程序和Package分析

    转载自 https://blog.csdn.net/kleguan/article/details/27538031 1. Linux抓包源程序 在OSI七层模型中,网卡工作在物理层和数据链路层的MA ...

  10. 刷题记录:[SUCTF 2019]EasySQL

    目录 刷题记录:[SUCTF 2019]EasySQL 一.涉及知识点 1.堆叠注入 2.set sql_mode=PIPES_AS_CONCAT;将||视为字符串的连接操作符而非或运算符 3.没有过 ...