从静态代理到JDK动态代理

it2024-12-07  16

前言:静态代理和动态代理是一种编程风格、编程范式,也叫设计模式

静态代理 public class StaticProxy implements Service{ public static void main(String[] args) { StaticProxy staticProxy=new StaticProxy(new DefaultService()); staticProxy.show(); } private Service service; public StaticProxy(Service service){ this.service=service; } @Override public void show() { System.out.println("Before"); service.show(); System.out.println("After"); } } interface Service{ void show(); } class DefaultService implements Service{ @Override public void show() { System.out.println("here is default show"); } }

2、 动态代理

public class JdkDynamicProxy { public static void main(String[] args) { byte[] bytes = ProxyGenerator.generateProxyClass("$ProxyDao", new Class[]{Dao.class}); try { FileOutputStream out = new FileOutputStream("C:\\Users\\23317\\Desktop\\$ProxyDao.class"); out.write(bytes); } catch (Exception ex) { } Object proxy = Proxy.newProxyInstance(JdkDynamicProxy.class.getClassLoader(), new Class[]{Dao.class}, new DaoInvocationHandler()); Dao dao = (Dao) proxy; dao.insert("qyd"); } } interface Dao { void insert(String name); } class DaoImpl implements Dao { @Override public void insert(String name) { System.out.println("insert->" + name); } } class DaoInvocationHandler implements InvocationHandler { private Dao dao = new DaoImpl(); /** * @param proxy 生成的$ProxyDao类的对象 * @param method $ProxyDao类实现的接口的对应方法 * @param args $ProxyDao类实现的接口的对应参数,用户传进来的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before"); method.invoke(dao, args); System.out.println("After"); return null; } } public final class $ProxyDao extends Proxy implements Dao { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $ProxyDao(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 insert(String var1) throws { try { super.h.invoke(this, m3, 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 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")); m3 = Class.forName("club.qydqyj.aop.Dao").getMethod("insert", Class.forName("java.lang.String")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }

总结: 1、动态代理即jdk帮我们实现了类,按照静态原理代码编写范式,动态代理的类也实现了接口 2、动态代理的类继承了Jdk的Proxy类,这也是jdk动态代理是基于接口的原因,因为java是单继承原则 3、动态代理类不但实现了接口的所有方法,也重写了Object类的equals、hashcode、toString方法 4、按照静态代理的代码编写范式,还需要实现了接口的类作为动态代理类的成员属性,以此来调用真正实现接口的方法。首先需要知道要代理的类应该由用户定义的,如果java设计成动态代理类为需要传进去所有接口的实现类作为参数交给java生成动态代理类,这样虽然也可以,但是显然有点设计过度。所以java设计了InvocationHandler类,java生成的动态代理类的所有重写方法都只调用InvocationHandler#invoke(Object proxy, Method method, Object[] args)方法,把真正接口实现的代码编写交给用户实现,这样明显更合理。 5、InvocationHandler#invoke(Object proxy, Method method, Object[] args)方法参数列表:proxy是java生成的动态代理类;method是接口方法和equals、hashcode、toString方法,args是用户传进去某方法的参数。

上帝视觉:

//1 Object proxy = Proxy.newProxyInstance(JdkDynamicProxy.class.getClassLoader(), new Class[]{Dao.class}, new DaoInvocationHandler()); //2 Dao dao = (Dao) proxy; //3 dao.insert("qyd");

1中的proxy就是Java生成的动态代理类,其实就是上面的$ProxyDao类的对象,这个类实现了接口Dao,当调用insert方法的时候,会调用重写的InvocationHandler类的方法,在这个方法里面,我们可以通过method对象知道当前正在哪个方法上,然后就可以通过method#invoke(要代理的类,args)调用真正实现接口的方法。这里有一个疑惑?为什么InvocationHandler#invoke方法参数会有proxy对象,由上面可以知道这个对象是java生成的动态代理类的对象,想不到有什么场景可以用到它?

最新回复(0)