深入理解java动态代理
2014-08-26 10:21
731 查看
昨天看spring aop(面向切面编程)时,遇到了java的动态代理问题。折腾了太多时间,大体弄明白了什么意思。
首先来看一下动态代理类的定义:动态代理实际上是一种设计模式。之所以称为动态,是因为 proxy类是在运行中才创建出来的,它是根据你创建的接口来实现(创建)的。
如上图所示,代理(HelloProxy)相当于一个经纪人,别人需要明星(HelloImpl)做一些事情的时候,首先要找的是代理。HelloProxy采用组合方式,实现了对HelloImpl的引用。明星说的一些可能不太合适,但是经过代理润色后可以更为恰当。这种方式还可以用来控制访问helloImpl的权限上。
上面的这种方式被称为静态代理。但是静态代理存在一个缺陷就是每当IHello增加一个接口方法,我们的HelloProxy就需要再写一次,实现对应的接口,有没有一种方式能够一劳永逸呢?我们可以用java动态代理来实现。
而动态代理则是java技术的核心。
首先来看一下动态代理的类图:
我们的明星在此类图中相当于user。他所能做的事情都在接口interfaceB当中。从上图手中我们可以看到,$prxoyN和user都实现了接口interfaceB。$prxoyN类继承自类Proxy。在静态代理当中,proxy类直接含有对实际要工作的对象的引用(明星),但在这里,$prxoyN实际引用的对象是AInocationHandler。AInocationHandler包含对user(明星)对象的引用。AInocationHandler同时实现了接口InvocationHandler,这其实是java在java.lang.reflect.InvocationHandler定义的接口。由于$proxyN 实现了所有的interfaceB接口,因此我们可以直接使用interfaceB userPrxoy=
(interfaceB)Proxy.newProxyInstance(User.getClass().getClassLoader(), User.getClass().getInterfaces(), iHandler);的方式来进行访问。在调用userPrxoy方法时,实际上userProxy通过AInocationHandler调用了User的方法。
我们只需要在AInocationHandler里重写接口方法
这样的好处是实现了松耦合,我们并不需要对实际的User类做出任何修改,就可以实现对其控制(自己理解)。在一些访问控制,日志管理中十分有效。
实际例子程序。
程序源码如下:
接口(=interfaceB)
被代理的类(=User)
s AInvocationHandler
classLoader作用是加载class文件的。我们可以利用Class clz=classLoader.loadClass("className");产生Class对象,然后利用
Object obj=clz.newInstance();来产生className对应的实例。
首先来看一下动态代理类的定义:动态代理实际上是一种设计模式。之所以称为动态,是因为 proxy类是在运行中才创建出来的,它是根据你创建的接口来实现(创建)的。
如上图所示,代理(HelloProxy)相当于一个经纪人,别人需要明星(HelloImpl)做一些事情的时候,首先要找的是代理。HelloProxy采用组合方式,实现了对HelloImpl的引用。明星说的一些可能不太合适,但是经过代理润色后可以更为恰当。这种方式还可以用来控制访问helloImpl的权限上。
上面的这种方式被称为静态代理。但是静态代理存在一个缺陷就是每当IHello增加一个接口方法,我们的HelloProxy就需要再写一次,实现对应的接口,有没有一种方式能够一劳永逸呢?我们可以用java动态代理来实现。
而动态代理则是java技术的核心。
首先来看一下动态代理的类图:
我们的明星在此类图中相当于user。他所能做的事情都在接口interfaceB当中。从上图手中我们可以看到,$prxoyN和user都实现了接口interfaceB。$prxoyN类继承自类Proxy。在静态代理当中,proxy类直接含有对实际要工作的对象的引用(明星),但在这里,$prxoyN实际引用的对象是AInocationHandler。AInocationHandler包含对user(明星)对象的引用。AInocationHandler同时实现了接口InvocationHandler,这其实是java在java.lang.reflect.InvocationHandler定义的接口。由于$proxyN 实现了所有的interfaceB接口,因此我们可以直接使用interfaceB userPrxoy=
(interfaceB)Proxy.newProxyInstance(User.getClass().getClassLoader(), User.getClass().getInterfaces(), iHandler);的方式来进行访问。在调用userPrxoy方法时,实际上userProxy通过AInocationHandler调用了User的方法。
我们只需要在AInocationHandler里重写接口方法
@Override public Object invoke(Object proxied, Method method, Object[] args) throws Throwable {//在整个方法当中 proxied一直没有用 //这里proxied传递过来的为 $proxyN对象实例。即在类<span style="font-family: Arial, Helvetica, sans-serif;">$proxyN中,其会这样调用invoke(this,method,args);</span> //可以写一些日志,如:System.out.println(method.getname+"方法被调用.....");以及通过method.getName判断调用的是哪个方法,来控制哪些方法不能被调用。 method.invoke(target, args);//实际user的方法,这里的target=user,注意这里 target不能用proxied,因为如果用proxied,就会再次进调用invoke方法,导致死循环的出现。 System.out.println("method.getname+"方法被调用完成.....""); return null; }
这样的好处是实现了松耦合,我们并不需要对实际的User类做出任何修改,就可以实现对其控制(自己理解)。在一些访问控制,日志管理中十分有效。
实际例子程序。
程序源码如下:
接口(=interfaceB)
package com.myproxy; public interface person { public void sayHello(); }
被代理的类(=User)
package com.myproxy; public class userImpl implements person{ @Override public void sayHello() { System.out.println("hello,i am a star"); } }
s AInvocationHandler
package com.myproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class AInvocationHandler implements InvocationHandler { private person p;//含有对实际被代理对象的引用 public AInvocationHandler(person p) { this.p=p; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("hello boys,and girls");//这其实是代理说出来的话,类似可以写一些日志类 System.out.println("即将被调用的方法是"+method.getName()); return method.invoke(this.p, args);//这里调用的是实际的被代理对象的引用 } }
package com.myproxy; import java.lang.reflect.Proxy; import com.proxy.UserManager; import com.proxy.invokeHandler; import com.proxy.managerInterface; import com.proxy.user; import java.lang.reflect.Proxy; public class test { public static void main(String []ars) { person p=new userImpl(); AInvocationHandler iHandler=new AInvocationHandler(p); person userProxy=(person)Proxy.newProxyInstance(p.getClass().getClassLoader(),p.getClass().getInterfaces(), iHandler); userProxy.sayHello(); } }
classLoader作用是加载class文件的。我们可以利用Class clz=classLoader.loadClass("className");产生Class对象,然后利用
Object obj=clz.newInstance();来产生className对应的实例。
相关文章推荐
- Java 动态代理深入理解
- 深入理解java动态代理机制
- 深入源码理解-java动态代理
- 深入理解JAVA JDK动态代理机制
- Java Reflection深入理解动态代理(Proxy)
- 深入理解JAVA JDK动态代理机制
- 深入理解java动态代理机制
- 深入理解Java动态代理及手动实现
- Java之深入理解JDK动态代理
- 黑马程序员_Java高新技术_动态代理技术的深入理解
- 深入理解 Java 动态代理机制
- 深入理解 Java 动态代理
- 深入理解java动态代理机制
- 对于java动态代理模式的深入理解
- 深入理解java动态代理的两种实现方式(JDK/Cglib)
- 深入理解Java的动态代理
- 深入理解动态代理(二)(网上总结的要点)
- 理解Java动态代理(1)—找我还钱?我出钱要你的命
- 轻松理解Java动态代理
- 轻松理解Java动态代理