深入理解JDK动态代理

编程

深入理解JDK动态代理" title="动态代理">动态代理

jdk动态代理" title="jdk动态代理">jdk动态代理是jre提供给我们的类库,可以直接使用,不依赖第三方,可以对接口方法进行增强。

创建接口

package com.ej.service;

public interface UserService {

String saveUser(String name,Integer age);

}

创建实现类

package com.ej.service.impl;

import com.ej.service.UserService;

public class UserServiceImpl implements UserService {

@Override

public String saveUser(String name, Integer age) {

String msg = "保存[" + name + "]的个人信息,年龄[" + age + "]岁";

System.out.println(msg);

return msg;

}

}

创建增强类

package com.ej.proxy.jdk;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

/**

* 必须要实现java.lang.reflect.InvocationHandler

* @author: Evan·Jiang

* @date: 2020/1/8 15:11

*/

public class JdkProxyHandler<T> implements InvocationHandler {

private T target;

public JdkProxyHandler(T target) {

this.target = target;

}

public T getTarget() {

return target;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

Object invoke = null;

try {

//执行前增强

System.out.println("执行目标方法前我可以干点啥呢???");

//执行目标方法

invoke = method.invoke(this.target, args);

} finally {

//执行后增强

System.out.println("执行目标方法后我还可以干点啥呢???");

}

return invoke;

}

}

创建代理对象

package com.ej.proxy.jdk;

import com.ej.service.UserService;

import com.ej.service.impl.UserServiceImpl;

import java.lang.reflect.Proxy;

public class JdkProxy {

public static <T> T getProxy(JdkProxyHandler<T> jdkProxyHandler) {

return (T) Proxy.newProxyInstance(

jdkProxyHandler.getTarget().getClass().getClassLoader(),

jdkProxyHandler.getTarget().getClass().getInterfaces(),

jdkProxyHandler

);

}

public static void main(String[] args) throws Exception {

//创建目标对象

UserService userService = new UserServiceImpl();

//创建增强对象

JdkProxyHandler<UserService> jdkProxyHandler = new JdkProxyHandler<>(userService);

//创建代理对象

userService = getProxy(jdkProxyHandler);

//执行代理对象方法

userService.saveUser("Evan", 66);

//忽略,为了进程不死

Thread.sleep(1000000L);

}

}

先看结果

执行目标方法前我可以干点啥呢???

保存[Evan]的个人信息,年龄[66]岁

执行目标方法后我还可以干点啥呢???

提几个问题

  • 代码userService.saveUser("Evan", 66);中userService到底是什么?
  • 代码userService.saveUser("Evan", 66);如果userService不是UserServiceImpl,那它为什么能调用saveUser方法
  • 为什么被代理的对象一定要实现至少一个接口?
  • 增强类为什么一定要实现java.lang.reflect.InvocationHandler接口?
  • 不需要UserServiceImpl行不行?

看看代理对象的真面目

先debug

当前代码执行到22行,userService为UserServiceImpl的实例 - 很正常的!

继续往下执行

...

当前代码执行到26行,userService为Proxy0的实例(即为代理对象) - 感觉已经和UserServiceImpl没什么关系了,但事实上是有关系的,看看图中的h和target。

看看Proxy0

Q:首先看看Proxy0到底是个什么东西?肯定是一个类,怎么看呢?

A:Arthas可以帮到我们

  • 启动Arthas找到的进程

  • 输入上图中的进程号前面的编号进入进程

  • 查找代理类得到完整类名

  • 反编译代理类

  • 把代码复制出来,写一写注释

package com.sun.proxy;

import com.ej.service.UserService;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0

//继承java.lang.reflect.Proxy类 - 看似废话,确回答了一个问题

extends Proxy

//实现com.ej.service.UserService接口 - 废话

implements UserService {

private static Method m1;

private static Method m2;

private static Method m3;

private static Method m0;

static {

try {

m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));

m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);

//接口的方法,有几个写几个

m3 = Class.forName("com.ej.service.UserService").getMethod("saveUser", Class.forName("java.lang.String"), Class.forName("java.lang.Integer"));

m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);

return;

}

catch (NoSuchMethodException noSuchMethodException) {

throw new NoSuchMethodError(noSuchMethodException.getMessage());

}

catch (ClassNotFoundException classNotFoundException) {

throw new NoClassDefFoundError(classNotFoundException.getMessage());

}

}

public $Proxy0(InvocationHandler invocationHandler) {

super(invocationHandler);

}

public final boolean equals(Object object) {

try {

return (Boolean)this.h.invoke(this, m1, new Object[]{object});

}

catch (Error | RuntimeException throwable) {

throw throwable;

}

catch (Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}

public final String toString() {

try {

return (String)this.h.invoke(this, m2, null);

}

catch (Error | RuntimeException throwable) {

throw throwable;

}

catch (Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}

public final String saveUser(String string, Integer n) {

try {

//this.h是父类java.lang.reflect.Proxy的属性

//类型为java.lang.reflect.InvocationHandler

//是不是回答了一个问题?

//m3:java.lang.reflect.InvocationHandler实现类的invoke方法中反射调用目标方法时用

return (String)this.h.invoke(this, m3, new Object[]{string, n});

}

catch (Error | RuntimeException throwable) {

throw throwable;

}

catch (Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}

public final int hashCode() {

try {

return (Integer)this.h.invoke(this, m0, null);

}

catch (Error | RuntimeException throwable) {

throw throwable;

}

catch (Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}

}

Proxy0是怎么来的

  • 给个线程栈

  • 构造类文件

问题解答

Q:代码userService.saveUser("Evan", 66);中userService到底是什么?

A:userService是Proxy0的实例

Q:代码userService.saveUser("Evan", 66);如果userService不是UserServiceImpl,那它为什么能调用

A:代理类实现了被代理对象的方法,所以userService代理实例能调用saveUser方法

Q : 为什么被代理的对象一定要实现至少一个接口?

A:Proxy0想要有saveUser方法可以选择继承UserServiceImpl类或者实现UserService接口,但是Proxy已经继承了java.lang.reflect.Proxy,Java不能多继承,所以只能选择实现接口

Q:增强类为什么一定要实现java.lang.reflect.InvocationHandler接口?

A:看看Proxy0的saveUser方法中this.h是父类java.lang.reflect.Proxy的属性字段,这个字段的类型就是java.lang.reflect.InvocationHandler,这里的值是我们自己定义的com.ej.proxy.jdk.JdkProxyHandler的实例,通过invoke直接调用【注意,这里并不是反射,真正的反射发生在com.ej.proxy.jdk.JdkProxyHandler类的invoke方法里面】

Q:不需要UserServiceImpl行不行?

A:这个问题就简单了,看看com.ej.proxy.jdk.JdkProxyHandler类的invoke方法,我们不调用目标方法不就行了,this.target就没鸟用了【RPC、Mybatis不就是这样吗】。

以上是 深入理解JDK动态代理 的全部内容, 来源链接: utcz.com/z/512484.html

回到顶部