Java编程之动态代理

来源:互联网 发布:卷皮和淘宝质量哪个好 编辑:程序博客网 时间:2024/06/06 02:48

代理:在实例的方法执行之前,由代理插入一段执行代码,然后调用实例的方法,之后也可以插入一段代码。这是AOP编程的核心。

在Java中实现动态代理有两种方式:
★ JDK动态代理 – 应用于代理实现了接口的类
★ cglib动态代理 – 主要应用于代理普通类(未实现接口)

先说说JDK动态代理
JDK动态代理主要依靠JavaAPI中的Proxy类,这个类中有个重要的方法

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
这是这个方法的英文解释,供参考。
对上面的方法做个理解:
ClassLoader loader 类加载器,加载被代理类的字节码。
Class<?>[] interfaces 被代理类实现的接口,代理类要和被代理类有相同的行为
InvocationHandler h 指定如何代理, 用到策略设计模式

案例一

//接口public interface Human {    void sing(float money);    void dance(float money);}
//实现类public class SpringBrother implements Human {    public void sing(float money) {        System.out.println("拿到:"+money+" 元开始唱歌");    }    public void dance(float money) {        System.out.println("拿到:"+money+" 元开始跳舞");    }}
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Client1 {    public static void main(String[] args) {        final Human sb = new SpringBrother();        //产生代理类,得到他的实例        Human proxyMan = (Human)Proxy.newProxyInstance(sb.getClass().getClassLoader(),                 sb.getClass().getInterfaces(),                 new InvocationHandler() {                    @Override                    public Object invoke(Object proxy, Method method, Object[] args)                            throws Throwable {                        if("sing".equals(method.getName())){                            //唱歌                            float money = (Float)args[0];                            if(money>10000){                                method.invoke(sb, money/2);                            }                        }                        if("dance".equals(method.getName())){                            //唱歌                            float money = (Float)args[0];                            if(money>20000){                                method.invoke(sb, money/2);                            }                        }                        return null;                    }                }        );        proxyMan.sing(20000);        proxyMan.dance(100000);    }}
运行结果:
   拿到钱:10000.0开唱   拿到钱:50000.0开跳

InvocationHandler是调用处理程序,每个代理类都对应一个调用处理程序
它是个接口,里面只有一个invoke()方法,每个类对其都有不同的实现,用到了策略设计模式

Object invoke(Object proxy, Method method, Object[] args)

Object proxy 对被代理对象的引用。
Method method 调用了被代理对象的哪个方法
Object[] args 当前方法用到的参数,没有则为null

再一个就是cglib动态代理

案例二

 public class SpringBrother{    public void sing(float money) {        System.out.println("拿到:"+money+" 元开唱");    }    public void dance(float money) {        System.out.println("拿到:"+money+"元开跳");    }}
import java.lang.reflect.Method;import net.sf.cglib.proxy.Callback;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class Client1 {    public static void main(String[] args) {        final SpringBrother sb = new SpringBrother();        /*        Class type:代理类的父类型        Callback cb:回调,如何代理         */        SpringBrother proxy = (SpringBrother) Enhancer.create(SpringBrother.class,new MethodInterceptor(){            public Object intercept(Object proxy, Method method, Object[] args,                    MethodProxy arg3) throws Throwable {                //判断出场费                if("sing".equals(method.getName())){                    //唱歌                    float money = (Float)args[0];                    if(money>10000){                        method.invoke(sb, money/2);                    }                }                if("dance".equals(method.getName())){                    //唱歌                    float money = (Float)args[0];                    if(money>20000){                        method.invoke(sb, money/2);                    }                }                return null;            }        });        System.out.println(proxy instanceof SpringBrother);        proxy.dance(100000);        proxy.sing(50000);    }}

运行结果:

   拿到钱:50000.0 元开跳   拿到:25000.0 元开唱

参考有关动态代理的原理了解底层原理

0 0