【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
深入理解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想要有save方法只能选择继承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不就是这样吗】。
来源:oschina
链接:https://my.oschina.net/u/4086878/blog/3154934