Java动态代理的实现方法

来源:互联网 发布:高中毕业学java 编辑:程序博客网 时间:2024/05/22 16:12

Spring AOP:Aspect Oriented Programming的缩写,意为面向切面编程,通过预编译方式和动态代理实现程序功能的统一维护的一种技术。扩展功能不修改源代码来实现,AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码 。说白了,就是为了增强方法的功能。
主要的功能有:日志记录,性能统计,安全控制,事务处理,异常处理等。

  1. 有接口和无接口的Spring AOP实现区别
    (1)Spring AOP默认使用标准的jdk动态代理作为AOP代理,这使得任何接口(或者接口集)都可以被代理。有接口情况,使用动态代理创建接口实现类代理对象。
    (2)Spring AOP中也可以使用CGLIB代理(如果一个业务对象并没有实现一个接口)。没有接口情况,使用动态代理创建类的子类代理对象,在子类中调用父类的方法完成增强。

  2. 两种动态代理的区别
    jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。


  1. 有接口情况,jdk动态代理的实现方法,代码如下:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;interface Hello{    public void toHello(String str);}/** * HelloImpl是Hello的实现类,复写toHello(String str)方法 * */class HelloImpl implements Hello{    public void toHello(String str)    {        System.out.println("HelloImpl........."+str);    }}class MyHandler implements InvocationHandler{    //要代理的原始对象    private Object obj;    public Object bind(Object obj)    {        this.obj = obj;        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);    }    /**    * 在代理实例上处理方法调用并返回结果    *     * @param proxy 代理类    * @param method 被代理的方法    * @param args 该方法的参数数组    */    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable    {        before();        Object result = method.invoke(obj, args);        after();        return result;    }    private void before()    {        System.out.println("方法增强before............");    }    private void after()    {        System.out.println("方法增强after.............");    }}public class ProxyDemo{    public static void main(String[] args)    {        MyHandler logHandler = new MyHandler();        Hello hello = (Hello) logHandler.bind(new HelloImpl());        hello.toHello("hello.....");    }}

打印的结果:
方法增强before............
HelloImpl.........hello.....
方法增强after.............

MyHandler类里的bind方法返回一个动态代理类,this指的是MyHandler的对象。this里面包含MyHandler类的invoke方法。

return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);

MyHandler类里的invoke(Object proxy, Method method, Object[] args)方法,重写了InvocationHandler接口中的invoke方法。method.invoke(obj, args),是java反射的invoke方法,里面的obj类就是main方法中调用的bind方法中传入的new HelloImpl()对象,args参数就是传入的”hello…..”参数,利用反射调用HelloImpl类里的toHello(String str)方法。

Object result = method.invoke(obj, args);

最后主函数中,logHandler.bind(new HelloImpl())是HelloImpl类的代理类,上升到接口层次,然后调用toHell(String str)方法,HelloImpl类又复写了Hello接口中的方法,所以执行HelloImpl类中的toHello(String str)方法,同时增强的方法也会被执行。

public class ProxyDemo{    public static void main(String[] args)    {        MyHandler logHandler = new MyHandler();        Hello hello = (Hello) logHandler.bind(new HelloImpl());        hello.toHello("hello.....");    }}

Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);产生代理对象,多了InvocationHandler参数(是InvocationHandler的实现类),它与代理对象关联,当请求分发到代理对象后,会自动执行invoke()方法,invoke()方法中就是我们可以写增强功能的地方。

有一个接口A,里面有一个方法c,类B实现A接口,原来是执行B类中的c方法,现在不这样做,声明一个B类的代理类B’,B’也实现接口A,B’应该也有c方法,调用它的时候,会去执行与它关联的InvocationHandler的invoke()方法,在invoke()方法里面可以写增强方法,增强方法也会被实现。强转为A接口类型,调用A接口中的方法c,实际上执行的还是A的实现类B中的c方法。


为什么非要创建一个代理类呢?为了代码的复用性。
例如:又创建了一个WorldImpl类,同样也需要增强它的功能,那我只需要在main方法中把该类作为一个参数传入到bind()方法就行了,但是前提是WorldImpl类必须实现一个接口World,才能使用jdk动态代理来实现拦截切入功能。代码如下:

package bean;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;interface Hello{    public void toHello(String str);}/** * HelloImpl是Hello的实现类,复写toHello(String str)方法 * */class HelloImpl implements Hello{    public void toHello(String str)    {        System.out.println("HelloImpl........."+str);    }}//===============================================interface World{    public void toWorld(String str);}class WorldImpl implements World{    public void toWorld(String str)    {        System.out.println("WorldImpl........."+str);    }}//===============================================class MyHandler implements InvocationHandler{    private Object obj;    public Object bind(Object obj)    {        this.obj = obj;        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);    }    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable    {        before();        Object result = method.invoke(obj, args);        after();        return result;    }    private void before()    {        System.out.println("方法增强before............");    }    private void after()    {        System.out.println("方法增强after.............");    }}public class ProxyDemo{    public static void main(String[] args)    {        MyHandler logHandler = new MyHandler();        Hello hello = (Hello) logHandler.bind(new HelloImpl());        hello.toHello("hello.....");        World world = (World) logHandler.bind(new WorldImpl());        world.toWorld("World.....");    }}

打印的结果:

方法增强before............HelloImpl.........hello.....方法增强after.............方法增强before............WorldImpl.........World.....方法增强after.............
原创粉丝点击