代理类是指在程序运行十创建的,可以根据调用处理器生成任何想要的结果。我们可以把面向对象理解为一个静态的过程,那么java动态代理就是面向对象的补充和完善。
动态代理demo
定义接口和实现类
public interface ProductDao {
void add();
void update();
void search();
void delete();
}
public class ProductDaoImpl implements ProductDao {
@Override
public void add() {
System.out.println("商品新增add");
}
@Override
public void update() {
System.out.println("商品修改update");
}
@Override
public void search() {
System.out.println("商品搜索search");
}
@Override
public void delete() {
System.out.println("商品删除delete");
}
}
实现代理工厂
public class JdkProxyFactory implements InvocationHandler {
public Object target;
public JdkProxyFactory(Object target){
this.target = target;
}
public Object createProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before(method);
Object result = method.invoke(target, args);
after(method);
return result;
}
private void after(Method method) {
// 目标方法执行后记录日志
System.out.println("日志记录:" + method.getName() + "执行结束了...");
}
private void before(Method method) {
// 目标方法执行前记录日志
System.out.println("日志记录:" + method.getName() + "开始执行了...");
}
}
测试类
public class JdkProxyFactoryTest {
public static void main(String[] args) {
ProductDaoImpl productDao = new ProductDaoImpl();
ProductDao proxyInstance = (ProductDao) new JdkProxyFactory(productDao).createProxyInstance();
//当执行这个方法时会执行代理方法,在方法前后增加日志
proxyInstance.add();
}
}
生成的代理类
类信息动态生成的二进制字节码保存到硬盘中
public class ProxyUtils {
public static void generateClassFiles(Class clazz,String proxyName){
/*
* params: clazz 需要生成动态代理类的类
* proxyName: 为动态生成的代理类的名称
*/
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String path = clazz.getResource(".").getPath();
System.out.println("path = " + path);
FileOutputStream out = null;
try{
out = new FileOutputStream(path + proxyName + ".class");
out.write(classFile);
out.flush();
}catch (Exception e){
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
测试类增加
ProxyUtils.generateClassFiles(productDao.getClass(),"proxyProductDao");
生成的代理类
在target包的相对路径下
public final class proxyProductDao extends Proxy implements ProductDao {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m6;
private static Method m0;
private static Method m4;
public proxyProductDao(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 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 add() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void delete() throws {
try {
super.h.invoke(this, m5, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void search() throws {
try {
super.h.invoke(this, m6, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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);
}
}
public final void update() throws {
try {
super.h.invoke(this, m4, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.my.dao.ProductDao").getMethod("add");
m5 = Class.forName("com.my.dao.ProductDao").getMethod("delete");
m6 = Class.forName("com.my.dao.ProductDao").getMethod("search");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m4 = Class.forName("com.my.dao.ProductDao").getMethod("update");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
通过这个代理类可以了解到以下几点
- JDK动态代理的目标类必须实现某个接口,这是由他的实现机制决定的
- 代理类的仅有一个构造函数,且唯一参数是InvocationHandler接口,这是给开发者自己实现的。
- 代理类执行方法时,可以直观看到实际上是执行的是自己是实现的invoke方法
源码解析
动态代理的实现依赖两个关键类
Proxy.newProxyInstance(ClassLoader classLoader,Interface[] interfaces,InvocationHandler h):构造实现指定接口的代理类的一个新实例,所有方法会调用给定处理器对象的 invoke 方法
InvocationHandler:定义了代理对象调用方法时希望执行的动作,用于集中处理在动态代理类对象上的方法调用
//简化代码
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
try {
//获取构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//反射获取对象
return cons.newInstance(new Object[]{h});
}
}
总结
优点:
- 动态代理减少了重复代码,提高了代码的可维护性和可读性。
- 通过动态代理,可以在不修改原始代码的情况下添加新的功能,如日志记录、性能监控等。
缺点: - 动态代理基于反射机制,可能会影响性能。
- 无法代理final类或方法,也无法代理static方法。