码迷,mamicode.com
首页 > 其他好文 > 详细

动态代理看这个就一目了然

时间:2018-10-24 17:52:56      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:proxy   发展   字节码   一个   pre   span   模式   应用   类加载器   

动态代理的总结

 

1.动态代理分类

我们设计一个应用的场景:

以前的导演剧组找演员的时候,直接到家里找这个演员谈价格就可以让他演戏,但是随着时代的发展,出现了经济公司,签约演员。 现在让演员演出就要直接找经济公司,不能找演员。

1.1基于接口的动态代理

// 创建一个演员的角色
public class Actor implements IActor {
?
    /**
     * 基本表演
     * @param money
     */
    @Override
    public void basicAct(Float money){
        System.out.println("拿到钱,开始基本的表演:"+money);
    }
?
    /**
     * 危险的表演
     * @param money
     */
    @Override
    public void dangerAct(Float money){
        System.out.println("拿到钱,开始危险的表演:"+money);
    }
}
?
?
?
// 模拟经济公司的标准
public interface IActor {
    /**
     * 基本表演
     * @param money
     */
    public void basicAct(Float money);
  
    /**
     * 危险的表演
     * @param money
     */
    public void dangerAct(Float money);
}

 


?

然后我们模拟一个剧组,通过经济公司来找演员,但是经济公司也有自己的标准,就是参数money

public class Client {
?
    public static void main(String[] args) {
        //早期:直接去家里找
        Actor actor = new Actor();
?
        //通过经纪公司来找演员
?
        IActor proxyActor = (IActor)Proxy.newProxyInstance(actor.getClass().getClassLoader(), actor.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 此处提供增强的代码
                     * 执行被代理对象的任何方法,都会经过该方法。
                     * @param proxy     代理对象的引用
                     * @param method    当前执行的方法
                     * @param args      当前方法所需的参数
                     * @return          和被代理对象的方法具有相同的返回值
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object rtValue = null;
                        //1.取出当前方法的参数
                        Float money= (Float) args[0];
                        //2.判断方法是什么
                        if("basicAct".equals(method.getName())){
                            //基本演出:抽取20% 要求一天5000块以上才接
                            if(money > 5000f){
                                rtValue = method.invoke(actor,money*0.8f);
                            }
                        }
                        if("dangerAct".equals(method.getName())){
                            //高危演出:抽取10% 要求一天20000块以上才接
                            if(money > 20000f){
                                rtValue = method.invoke(actor,money*0.9f);
                            }
                        }
                        return rtValue;
                    }
                });
?
?
        proxyActor.basicAct(10000f);
        proxyActor.dangerAct(50000f);
    }
}
?

 

运行结果:

拿到钱,开始基本的表演:8000.0拿到钱,开始危险的表演:45000.0

总结:


动态代理基于接口
        * 作用:不修改源码的基础上,对已有方法增强
        * 特点:字节码是随用随创建,随用随加载。
        * 基于接口的动态代理:
        * 提供者:JDK官方
        * 要求:被代理对象最少实现一个接口。
        * 涉及的类:Proxy
        * 涉及的方法:newProxyInstance
        * 方法的参数:
        *     ClassLoader:类加载器。负责加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
        *     Class[]:字节码数组。代理对象具有的方法。和被代理对象实现相同的接口。
        *               如果被代理对象本身是一个接口的话,直接把被代理对象存入字节码数组中。
        *               xxx.getClass().getInterfaces() || new Class[]{xxx}
        *               固定写法。
        *     InvocationHandler:如何代理的接口。谁用谁写。用于增强方法的。需要我们自己提供一个该接口的实现类。
        *                         通常情况下可以写成匿名内部类。
        *                         策略模式:
        *                             数据已经有了
        *                             目的明确。
        *                             达成目标的过程即是策略。

 

1.2基于子类的动态代理

 

public class Actor {
?
     /**
     * 基本表演
     * @param money
     */
?
    public void basicAct(Float money){
        System.out.println("拿到钱,开始基本的表演cglib:"+money);
    }
?
     /**
     * 危险的表演
     */
     
?
    public void dangerAct(Float money){
        System.out.println("拿到钱,开始危险的表演cglib:"+money);
    }
}
?
?
?
?
public class Client {
?
    public static void main(String[] args) {
        // 早期:直接去家里找
        // Actor actor = new Actor();
        // 通过经纪公司来找演员      
/**
         * 动态代理
         *  作用:不修改源码的基础上,对已有方法增强
         *  特点:字节码是随用随创建,随用随加载。
         *  基于子类的动态代理:
         *  提供者:第三方cglib库
         *  要求:被代理对象不能是最终类。不能被final修饰
         *  涉及的类:Enhancer
         *  涉及的方法:create
         *  方法的参数:
         *      Class:字节码。被代理对象的字节码。固定写法。
?
         *      Callback:如何代理的接口。谁用谁写。用于增强方法的。需要我们自己提供一个该接口的实现类。
         *                         通常情况下可以写成匿名内部类。
         *                         我们需要使用它的子接口:MethodInterceptor
         *                         策略模式:
         *                              数据已经有了
         *                              目的明确。
         *                              达成目标的过程即是策略。
         *
         */
        Actor cglibActor = (Actor) Enhancer.create(actor.getClass(), new MethodInterceptor() {
       
             /**
             * 此处提供增强的代码
             * 执行被代理对象的任何方法,都会经过该方法。
             * @param proxy         代理对象的引用
             * @param method        当前执行的方法
             * @param args          当前方法所需的参数
             * @param methodProxy   当前方法的代理对象
             * @return              和被代理对象的方法具有相同的返回值
             * @throws Throwable
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object rtValue = null;
                // 1.取出当前方法的参数
                Float money= (Float) args[0];
                // 2.判断方法是什么
                if("basicAct".equals(method.getName())){
                    // 基本演出:抽取20% 要求一天5000块以上才接
                    if(money > 5000f){
                        rtValue = method.invoke(actor,money*0.75f);
                    }
                }
                if("dangerAct".equals(method.getName())){
                    // 高危演出:抽取10% 要求一天20000块以上才接
                    if(money > 20000f){
                        rtValue = method.invoke(actor,money*0.85f);
                    }
                }
                return rtValue;
            }
        });
        cglibActor.basicAct(10000f);
        cglibActor.dangerAct(50000f);
    }
}

动态代理看这个就一目了然

标签:proxy   发展   字节码   一个   pre   span   模式   应用   类加载器   

原文地址:https://www.cnblogs.com/mudi/p/9844536.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!