java JDK动态代理的机制

一:前言

  自己在稳固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、计算机网络等。还有好远的路要走啊。明天在写篇自己这块三个月的感感想吧。记录下自己的感受。努力加油,一天一天的进步。努力!!!

 

posted @ 2014-10-14 17:01  郁闷的耗子  阅读(535)  评论(0编辑  收藏  举报