JAVA动态代理的作用

来源:互联网 发布:游戏编程c语言 编辑:程序博客网 时间:2024/06/07 04:10

先定义一个接口类,该接口是我们要代理的接口


public interface Subject{public void rent();public void hello(String str);}

接下来是一个实现类


public class RealSubject implements Subject{@Overridepublic void rent(){System.out.println("i want to rent my house");}@Overridepublic void hello(String str){System.out.println("hello:"+str);}}

接下来是动态代理类, 该类必须实现InvocationHandler接口


public class DynamicProxy implements InvocationHandler{private Object subject;public DynamicProxy(Object subject){super();this.subject = subject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable{System.out.println("before method:" + method.getName());method.invoke(subject, args);System.out.println(method);System.out.println("after method:" + method.getName());return subject;}}


接下来是测试类,用来测试动态代理的机制,以及作用


/* * 动态代理的作用: * 在实现要代理的对象的核心功能的基础上 * 添加额外的一些功能 */public class Client{@Testpublic void mainTest(){// 利用代理机制创建了一个跟realSubject实现了相同接口的类Subject realSubject = new RealSubject();InvocationHandler handler = new DynamicProxy(realSubject);// 制定要创建的代理实例使用的ClassLoader、要实现的哪些接口、代理该实例的代理类(invocationHandler)Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[]{ Subject.class }, handler);System.out.println(subject.getClass().getName() + "与" + realSubject+ "作比较");realSubject = null;subject.rent();subject.hello("world");}@Testpublic void myProxy(){Subject realSubject = new RealSubject();Class[] intefaces = realSubject.getClass().getInterfaces();for (Class t : intefaces){System.out.println("接口:" + t + "===========");Method[] methods = t.getMethods();for (Method m : methods){System.out.println("执行方法:" + m.getName() + "=======");System.out.println("before====>" + m.getName());try{Class[] params = m.getParameterTypes();if (params != null && params.length > 0){m.invoke(realSubject, "World");} else{m.invoke(realSubject);}} catch (IllegalAccessException | IllegalArgumentException| InvocationTargetException e){e.printStackTrace();}System.out.println("after====>" + m.getName());}}}@Testpublic void myProxy2(){Subject realSubject = new RealSubject();Method rent;try{rent = realSubject.getClass().getMethod("rent");System.out.println("执行方法:" + rent.getName() + "=======");System.out.println("before====>" + rent.getName());rent.invoke(realSubject);System.out.println("after====>" + rent.getName());} catch (NoSuchMethodException | SecurityException e){e.printStackTrace();} catch (IllegalAccessException e){e.printStackTrace();} catch (IllegalArgumentException e){e.printStackTrace();} catch (InvocationTargetException e){e.printStackTrace();}}}


mainTest方法创建了一个realSubject的动态代理实例subject,当调用subject的方法时,会自动调用handler对象里面的invoke方法,在invoke方法里面,会调用我们要代理的对象(realSubject)的方法,我们可以在调用realSubject对象的方法前后加上一些其他的逻辑,这也是Spring AOP机制的实现原理

在看动态代理机制时,我有一个疑问,就是为什么要用到动态代理,需求何在?

网上搜了很多资料,很多答案都文绉绉的,看起来不是很好懂,就我自己的理解,使用动态代理,其实就是为了方便在实现一个对象的某个方法前后,添加一些其他的逻辑,如上的myProxy2()方法,使用反射也可以达到这个目的,但是这样的实现想比动态代理而言,逻辑性比较差,而且当动态代理使用的地方有多处时,前后添加的逻辑没能聚拢到一个地方,每次都要反射拿到方法,然后在执行方法的前后再添加逻辑,这样用不好维护,如果用动态代理,虽然创建代理对象时比较麻烦,但是当代理对象创建好以后,可以直接使用例如 subject.rent(); 这样的方式,直接调用方法,前后添加的逻辑在hanlder的invoke方法里面已经实现好了

 要注意的一点是,subject对象实际上不是一个Subject类或者RealSubject类,而是一个com.sun.proxy.$Proxy这样的类

在handler对象的invoke方法里面,参数Object proxy 实际上没用用到,如果试着去打印出这个参数,会报错,具体原因我也不清楚,使用该方法,实际上用的是创建该handler时传进去的realSubject对象,而使用代理对象subject的方法时,会去调用handler里面的invoker方法,所以,当我们调用代理对象subject的方法时,其实是调用了真实对象

realSubject的方法


以上都是个人见解,如果有不对的地方,恳请大家帮忙指出,感激不尽


0 0
原创粉丝点击