Java动态代理(举例)

Posted on 2013-05-25 21:24  bokeyuan123465  阅读(1077)  评论(1编辑  收藏  举报

     通过JDK实现动态代理,有代理需求的类(这里称之为实现类)必须要实现接口。动态代理可以将逻辑切片,通过代理类(proxy)代实现类实现逻辑,期间还可以进行一些其他的操作。JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一 起。关于动态这块儿一直比较迷惑,傻傻分不清楚,今天又有了新的理解,下面通过一个简单的例子来说明:

   先叙述下事务逻辑:一个人(people对象)通过交通工具(Transportation处理类)去了外国(日本、英国)

  1、将去英国和日本这两件事当做两个接口,由人来实现

   

package com.impetention.lei;

public interface Japan
{
   public void goJapan();
}
--------------------------------------------
package com.impetention.lei;

public interface England
{
    public void goEngland();
}
-------------------------------------------------
package com.impetention.lei;
//实现类
public class People implements England,Japan
{
    @Override
    public void goEngland()
    {
        // TODO Auto-generated method stub
        System.out.println("I am in England !");
    }

    @Override
    public void goJapan()
    {
        // TODO Auto-generated method stub
        System.out.println("I am in Japan !");
    }

}

2、现在介绍一下InvocationHandler ,它是代理类的调用处理程序 实现的接口。每个代理类都具有一个关联的调用处理程序,在实例化代理类时会添加进去一个InvocationHandler类型的处理类(完成事务逻辑的主题)。

如:

package com.invocation;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.impetention.lei.People;

//人通过交通工具(代理)去国外
public class Transportation implements InvocationHandler
{
    //一个叫zhang的人
    private Object zhang = null;
    
    public Transportation(Object zhang)
    {
        this.zhang = zhang;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
    {
        // TODO Auto-generated method stub
        System.out.println("可以执行一些其他方法.....");
        //记录执行结果
        Object result = null;
        zhang = new People();
        //在zhang对象上执行method方法,并将结果返回
        try
        {
            result = method.invoke(zhang, args);
        } catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("---------------------");
        return result;
    }

}

注意里面红色的proxy,它就是代理类实例。这里有必要对invoke(Object proxy, Method method, Object[] args) 做出一些解释,动态代理类proxy0调用goEngland()方法时会调用它自己的goEngland()方法, 而它自己的goEngland()方法里面调用的是其绑定对象InvocationHandler对象的invoke()方法, 也就是Transportation的invoke方法。invoke(Object proxy, Method m, Object[] args)种的proxy实际上就是动态代理类proxy, 如果你将其强转成England然后调用它的goEngland()方法,它又会触发代理类的goEngland()方法,代理类又调用InvocationHandler(transportation)的invoke()方法,这样就会死循环。

 

 3、代理实现:

package com.main;

import java.lang.reflect.Proxy;

import com.impetention.lei.England;
import com.impetention.lei.Japan;
import com.impetention.lei.People;
import com.invocation.Transportation;

public class Peopletest
{
    public static void main(String[] args)
    {
        //准备用动态代理实现,一个叫li的人通过交通工具到了英国
        England li = new People();
        //实例化transportation对象
        Transportation t1 = new Transportation(li);
        //通过li.getClass().getClassLoader()实现类的类加载器和li.getClass().getInterfaces()实现类实现的所有接口作为参数调用                 
//Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)的方法返回代理类的java.lang.Class对象获得了一个proxy代理类,
//必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类方法执行前后做额外工作的类transpotation。将代理类强转成England类型
England proxy = (England) Proxy.newProxyInstance(li.getClass().getClassLoader(),
                li.getClass().getInterfaces(), t1);
        proxy.goEngland();
        //准备用动态代理实现,一个叫li的人通过交通工具到了英国
                Japan lei = new People();
                //实例化transportation对象
                Transportation t2 = new Transportation(lei);
                //通过li.getClass().getClassLoader()和li.getClass().getInterfaces()获得了一个
                //(java.lang.class)proxy代理类,并以tt为参数对其进行实例化,强转成people类型
                Japan proxy1 = (Japan) Proxy.newProxyInstance(li.getClass().getClassLoader(),
                        li.getClass().getInterfaces(), t2);
                proxy1.goJapan();
        
        
    }
}
小结:过程是这样的,people执行goEngland()方法不直接执行,而是通过代理类proxy,proxy执行它自己的goEngland(),会触发Transportation调用invoke(),然后
method.invoke(zhang, args);zhang会调用它的method,即goEngland(),最后将结果返回。

Copyright © 2024 bokeyuan123465
Powered by .NET 8.0 on Kubernetes