今天给大家带来的是使用arthas的jad命令来反编译字节码,查看JDK代理的产物。话不多说,直接进入正题。
首先有如下一些简单的java代码
UserService
public interface UserService {
public boolean login(String username, String password);
}
UserServiceImpl
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public boolean login(String username, String password) {
log.info("username:{}, password:{}", username, password);
return false;
}
}
MyInvocationHandler
@Slf4j
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("before invoke");
Object res = method.invoke(target, args);
log.info("after invoke");
return res;
}
}
ProxyMain
@Slf4j
public class ProxyMain {
public static void main(String[] args) throws InterruptedException {
UserService target = new UserServiceImpl();
UserService userService = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new MyInvocationHandler(target));
userService.login("zhq123", "123456");
log.info("proxy class:{}", userService.getClass());
Thread.sleep(Long.MAX_VALUE);
}
}
pom.xml
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
接下来直接运行代码,日志输出如下:
20:27:20.529 [main] INFO com.zhq.proxy.MyInvocationHandler - before invoke
20:27:20.530 [main] INFO com.zhq.proxy.UserServiceImpl - username:zhq123, password:123456
20:27:20.531 [main] INFO com.zhq.proxy.MyInvocationHandler - after invoke
20:27:20.531 [main] INFO com.zhq.proxy.ProxyMain - proxy class:class com.sun.proxy.$Proxy0
接下来我们打开arthas工具,没有的小伙伴可以前往arthas官网下载arthas.aliyun.com/doc/install… 执行如下命令
java -jar .\arthas-boot.jar
在终端输出的结果中找到我们需要连接的java程序的编号,我这里是2,直接输入2即可
接下来执行jad命令,获取反编译后的java代码
jad com.sun.proxy.$Proxy0
得到如下java代码
public final class $Proxy0
extends Proxy
implements UserService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
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.zhq.proxy.UserService").getMethod("login", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
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 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 int hashCode() {
try {
return (Integer)this.h.invoke(this, m0, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean login(String string, String string2) {
try {
return (Boolean)this.h.invoke(this, m3, new Object[]{string, string2});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
通过这样的操作,希望能够让大家更好的理解动态代理。