弥补静态代理会产生类爆炸的缺点,动态代理营运而生。JDK动态代理只能代理接口(因为动态代理生成的代理类已经继承了Proxy,所以只能代理接口)
实现JDK动态代理有哪些步骤呢
1,新建一个接口并新建其实现类(JDK动态代理中称之为目标对象即targetObject)
2,新建代理类实现InvocationHandler接口重写invoke方法
先上个简单的图,不喜勿喷
下面请看代码演示
public interface UserDao {
void query(String id);
void insert(int id,String name);
}
public class UserDaoImpl implements UserDao {
@Override
public void query(String id) {
System.out.println("query db --id:"+id);
}
@Override
public void insert(int id, String name) {
System.out.println("insert db --id:"+id+"--name:"+name);
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserDaoProxy implements InvocationHandler {
UserDao target;//目标对象UserDaoImpl
public UserDaoProxy(UserDao target){
this.target = target;
}
public Object getInstance(){//通过Proxy对象 根据 目标对象 创建其 代理对象
Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return object;
}
//proxy 代理对象 即 $Proxy0
//targetMethod 目标对象的query,insert方法
//targetArgs 目标对象的参数 [110] , [1,222]
@Override
public Object invoke(Object proxy, Method targetMethod, Object[] targetArgs) throws Throwable {
sout("aop before......")
return targetMethod.invoke(target,targetArgs);
sout("aop after......")
}
}
public class Test {
public static void main(String[] args) {
//目标对象
UserDao target = new UserDaoImpl();
//代理类对象
UserDaoProxy proxyClass = new UserDaoProxy(target);
//代理对象
UserDao Proxy =(UserDao) proxyClass.getInstance();
Proxy.query("110");
Proxy.insert(1,"222");
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
}
}
实现InvocationHandler接口 debug调试程序(非源码)
这儿有2个对象,分别是target 目标对象 即 UserDaoImpl
proxyClass 代理类对象 产生代理对象 和 代理执行目标对象的方法
下面进去看第三个对象代理对象 这个代理对象应该是 $Proxy 开头的
这边的三个对象
第一个是当前类的类对象即代理类对象就是上图的那个proxyClass = UserDaoProxy@626
第二个对象object={$Proxy0@657} 这个对象就是回返的代理对象 $Proxy 开头的
第三个对象是代理对象target 就是上图的target = UserDaoImpl@623的
继续回来看返回的代理对象 就是那个$Proxy 开头的
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
通过这行代码可以看到底层帮我们创建的代理对象$Proxy0,可以知道为什么只能代理接口了,因为Java语法限制理想情况下只能单继承
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.dao.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements UserDao {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void query(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void insert(int var1, String var2) throws {
try {
super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.dao.UserDao").getMethod("query", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.dao.UserDao").getMethod("insert", Integer.TYPE, Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
我们下面看下jdk动态代理底层是如何帮我们实现的
本周五更新