一:前言
自己在稳固spring的一些特性的时候在网上看到了遮掩的一句话“利用接口的方式,spring aop将默认通过JDK的动态代理来实现代理类,不适用接口时spring aop将使用通过cglib 来实现代理类",我对JDK的动态代理机制其实一点都不了解,学习java的时候也是只是知道会用,会去查api的文档就行,所以这些底层的操作方式我自己不是很清楚,现在既然要了解一些底层的代码,就谢谢自己的想发,大部分都是差不多的。
二:实现
先给出接口和实现类的代码:
UserDao.java:
package dynamicProxy; public interface UserDao { String saveUser(String name); void deleteUser(String name); }
UserDaoImpl.java:
package dynamicProxy; public class UserDaoImpl implements UserDao{ @Override public String saveUser(String name) { System.out.println("姓名:"+name); return name; } @Override public void deleteUser(String name) { System.out.println("要删除的姓名:"+name); } }
既然都说了是JDK的动态代理,那么现在我们需要些一个累来实现"java.lang.reflect.InvocationHandler"的接口,里面有invoke(*,*,*)方法,该方法有三个参数,参数意思下面会说给出代码如下:
package dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MouseHandler implements InvocationHandler { private Object target; public MouseHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理的类为:"+proxy.getClass()); System.out.println("目标类:"+target.getClass()+"target对象--->"+target); System.out.println("方法:"+method); System.out.println("参数:"+args); System.out.println("开始输出日志"); Object obj=method.invoke(target, args); System.out.println("obj的值:"+obj); return obj; } }
当你自己把这些参数全部打印出来了,就会知道参数的意思。下面我写下来了
Object proxy:要代理的类(打印结果为------>代理的类为:class $Proxy0)
Method method:这里的method是指要调用得方法(打印结果-------->方法:public abstract java.lang.String dynamicProxy.UserDao.saveUser(java.lang.String))
Object[] args:这里是参数数组,就是该方法的参数
还有就是这个方法(public Object invoke(Object proxy, Method method, Object[] args))最后我们返回的值:返回的值就是我们调用该方法,该方法返回的值 (输出结果为---->obj的值:老鼠)
再来说说这和Object proxy,如果你在method.invoke(proxy,args)这里的第一个参数依然使用proxy(自动生成的代理类)的话,在运行程序你会发现程勋会一会运行(报错),一直循环,错误代码如下:
这里需要指定要代理的对象。
下面在看看Test.java类
package dynamicProxy; import java.lang.reflect.Proxy; public class Test { public static void main(String args[]){ UserDao userDao=new UserDaoImpl(); System.out.println("-->"+userDao.getClass().getClassLoader());//(打印结果:-->sun.misc.Launcher$AppClassLoader@addbf1) System.out.println("-->"+userDao.getClass().getInterfaces());//(打印结果:-->[Ljava.lang.Class;@61de33) UserDao userDaoProxy=(UserDao)Proxy .newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces() , new MouseHandler(userDao)); userDaoProxy.saveUser("老鼠"); } }
看看Proxy(*,*,*)方法中的三个参数
userDao.getClass().getClassLoader():这是类加载器
userDao.getClass().getInterfaces():代理的接口
new MouseHandler(userDao):实例化传入需要代理的对象(对UserDaoImpl的引用)
如果你再加断点调试的话就会发现,其实MouseHandler中的invoke方法只有在调用方法userDaoProxy.saveUser("老鼠");的时候才会执行,也就是说调用得是saveUser("老鼠"),实际上时在调用invoke方法。上面的知识其实有的也是看看网上的资料,在结合下来写的,但是真正需要自己断点来运行下
其实现在我在理解底层代码,很多都是需要自己来敲一遍,自己断点运行,自己来调试,只有这样自己的理解才会会更加的彻底。这几天算是把spring ioc和aop给理解了一遍,IOC还好,但是aop自己觉得理解起来好是郁闷啊。不过我还是回尽量的去理解,这对自己还是有好处的。明天就是我自己的生日了,这是我出社会(还未毕业的出社会)第一次过生日,写篇博客提前祝自己生日快乐吧。实习已经快3个月了,不敢说自己现在又多么多么的牛逼,但是真的觉得自己进步了,自己有了方向感,自己知道需要去学习些什么东西。这一点很是重要。以前虽然也知道要学java,但是只是懂了皮毛,真正的东西还是不理解。这就是基础。最近在补习很多东西,java、linux、计算机网络等。还有好远的路要走啊。明天在写篇自己这块三个月的感感想吧。记录下自己的感受。努力加油,一天一天的进步。努力!!!