最近呢和动态代理发生了一些故事。从相识,到相知,到今天520,写写博客。算是对动态代理有一个交代。下一步转战rabbitMQ,没办法MQ和动态代理就没法比,因为就是两个东西。
由于早早的就知道了动态代理的美名,所以特地针对它做了一番布置。基本上就是从简单,到复杂,到深入的这么一个过程。
1、从基本概念入手,多多了解,足够了解了才能好好的嘛。这部分主要是静态代理,还有动态代理的一些基本概念。
2、深入发展,参考一些论坛,博客,尤其是百度,看看动态代理都有哪些特质,动态代理的一些代码。多参考一些博客,不止看一篇博客,多看几篇,这样才会不至于自己理解的有所偏执。
3、打入内部,看看动态代理的源码部分。仍旧百度,博客,可以找一些书看看。深度随意。
4、动态代理是我的了,把自己的知识和动态代理糅杂在一起。这样就不容易分开了。结合自己所学,再找一些稍微复杂的demo,加强理解和应用。
5、带着动态代理溜溜去。带着动态代理的经典应用去看看框架里是怎么应用的。
静态代理
我们为什么要采用代理模式呢,根据它的特点,我们知道代理对象可以实现面向切面的这种编程实现。那么一些公共的内容就可以放在代理对象的方法里,业务逻辑代码放在真正对象里,做到让程序员只关注业务实现,其他的类似事务处理,日志打印等程序员不必关心。
下面先来个类图:在实现静态代理的过程中,我们需要建立一个真正对象,放在项目里也就是Service实现,也需要一个代理对象。最后在调用代理对象的方法。其中可以在代理对象方法中,嵌入非业务方法。比如事务的开启,提交或回滚。
public interface Action { void send(String str); } public class Person implements Action{ @Override public void send(String str) { System.out.println(str); } } public class ProxyPerson implements Action { private Action action; ProxyPerson(Action action){ this.action = action; } @Override public void send(String str) { System.out.println("执行业务方法前:开启事务了"); this.action.send(str); System.out.println("执行业务方法后:事务提交/回滚了"); } } public class TestProxy { public static void main(String[] args) { Person person = new Person(); ProxyPerson proxy = new ProxyPerson(person); proxy.send("论520与250的区别"); } }
但是项目中有很多的Service,难道我们要建立很多代理对象吗?下面就来看看动态代理对象是怎么解决这个问题的,当然解决这个问题可以有各种各样的办法,但动态代理是目前最好的一种实现方法,为什么呢?因为好多框架都采用这种方式。
动态代理
动态代理是静态代理的进一步实现,现在本人了解到的有jdk动态代理实现和cglib的动态代理实现。其中jdk动态代理是根据业务对象的接口,采用字节码动态生成一个动态代理类。而cglib采用继承的方式动态生成一个子类。jdk的实现,必须有一个
InvocationHandler的实现。
代码实现
public interface UserService { String getInfo(); } public class UserServiceImpl implements UserService { @Override public String getInfo() { return "Service 实现"; } } public class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try{ System.out.println("Service 实现前"); System.out.println("方法名" + method.getName()); Object result = method.invoke(target,args); System.out.println(result); System.out.println("Service 实现后"); return result; }catch (Exception e){ throw e; } } }
测试代码
public class ProxyTest { public static void main(String[] args) throws Exception { // System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); UserService service = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(service); UserService infoService = (UserService) Proxy.newProxyInstance( service.getClass().getClassLoader(), service.getClass().getInterfaces(), handler); String info = infoService.getInfo(); System.out.println(info); //以下方法是把动态类生成到文件里。 byte[] proxyClass = ProxyGenerator.generateProxyClass(infoService.getClass() .getSimpleName(), infoService.getClass().getInterfaces()); //将字节码文件保存到D盘,文件名为$Proxy0.class FileOutputStream outputStream = new FileOutputStream(new File( "d:\\$Proxy0.class")); outputStream.write(proxyClass); outputStream.flush(); outputStream.close(); }
接触jdk动态代理的源码
一下是基于个人的理解,有所偏颇,还请指正。jdk动态代理是首先从缓存里获取动态代理类,如果没有的话,创建一个,然后放入缓存里。下次的话直接从缓存里获取吧。其中生成动态类的字节码是通过 ProxyGenerator.generateProxyClass方法生成。然后根据构造器的newInstance方法,返回动态代理类的实例。在阅读源码中的收获呢,其中知道了弱引用在这有用的,还有生成动态代理类的类名是$Proxy0,其中后面的这个0数字通过AtomicInteger进行的。知道了一些原子类类型的简单应用。加强了对动态代理的印象。下面看下动态代理类的代码。
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 var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } 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 String getInfo() throws { try { return (String)super.h.invoke(this, m3, (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)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.ssm.proxy.UserService").getMethod("getInfo", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
从上面构造函数,以及getInfo方法,我们就知道为什么一定需要InvocationHandler的实现类了。因为调用动态代理类的方法时,真正调用的其实是InvocationHandler的invoke方法。