代理模式--JDK动态代理案例

一、概念

1.真实对象:被代理的对象

2.代理对象:咱们写的本身

3.代理模式:代理对象代理真实对象,达到增强真实对象的功能和目的。

4.实现方式:动态代理在内存中形成代理类,代理对象和真实对象必须实现相同接口。

原理:利用反射生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

二、JDK动态代理--生活代码案例

通过以上生活案例,我们来写代码,总是代理模式和生活的意思一样,现在商业处处都是代理,买房子,微商等等,有了这些代理,客户获取了更好的感受。

1.卖电脑接口2

/**
 * 真实对象和代理对象实现相同的卖电脑接口
 */
public interface SaleComputer {

    String pay(double money);

    void show();
}

2.北京联想公司(真实对象)

public class Lenovo implements SaleComputer {
    @Override
    public String pay(double money) {

        System.out.println("客户支付了"+money+"买了一台电脑");
        return "联想电脑";
    }

    @Override
    public void show() {
        System.out.println("展示电脑");
    }
}

3.天津代理商(代理对象)

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

/**
 * 增强代理对象测试
 */
public class ProxyTest {
    public static void main(String[] args) {

        Lenovo lenovo = new Lenovo();
        /*
         *  java.lang.reflect.Proxy提供用于创建动态代理类和实例的静态方法,大家可以查看JDK文档。
         *  1.Proxy.newProxyInstance()通过调用newInstance 方法创建代理实例。
         *  2.方法中有三个参数
         *      ClassLoader loader:定义代理类的类加载器(即真实对象)
         *      Class<?>[] interfaces:真实对象实现的接口数组
         *      InvocationHandler h:调用处理程序,执行方法。
         */

        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(),
                lenovo.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            //invoke方法是核心代理逻辑思想,代理对象调用的所有方法都会触发该方法执行
            //增强方式有三种:1.增强参数 2.增强返回值 3.增强方法体
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                /*
                 * 三个参数
                 *      1.proxy:就是代理对象本身
                 *      2.method:代理对象调用的方法,被封装为的对象。简单说 谁在运行调用,这个method就是谁。
                 *      3.args:代理对象调用方法时,传递的实际参数
                 */


                    //增强参数
                if (method.getName().equals("pay")) {
                    //增强参数,代理需要赚取利润,代理修改了参数。
                    //这里args[0]代表方法的第一个参数。
                    double money = (double) args[0];
                    money = money * 1.2;
                    //增强方法体
                    System.out.println("买电脑专车接送");

                    //修改了方法参数 这里method.invok就是调用方法。
                    String computer = (String) method.invoke(lenovo, money);

                    //增强方法体
                    System.out.println("买电脑免费配送");

                    //增强返回值
                    return computer+"送鼠标垫";
                } else {
                    //如果没有,那么就原样输出
                    Object obj = method.invoke(lenovo, args);
                    return obj;
                }
            }
        });


        String computer = proxy_lenovo.pay(5000);
        System.out.println(computer);

        proxy_lenovo.show();
    }
}

4.测试结果

 三、JDK动态代理--业务逻辑案例

在我们web项目开发中,业务层存在UserService接口,其中有查询所有用户,删除用户等业务逻辑,UserServiceImpl实现类重写方法。我们要对每个方法进行性能分析,检测每个方法的消耗时间,那么我们可以不改变原有类的基础上增强对象。

1.UserService接口

public interface UserService {
    /**
     * 查询用户
     */
    void getUsers();

    /**
     * 删除用户
     */
    void deleteUser();
}

2.UserServiceImpl实现类

public class UserServiceImpl implements UserService {
    @Override
    public void getUsers() {

        try {
            /**
             * 这里让他睡一下,咱们这个业务逻辑只是输出一句话
             * 没有做真正的业务查询,不然运行太快
             */
            Thread.sleep(1000);
            System.out.println("查询了100个用户");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteUser() {
        try {
            Thread.sleep(2000);
            System.out.println("删除了50个用户");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3.定义一个获取代理对象的工具类

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

public class ProxyUtil {

    public static UserService getProxy(UserServiceImpl obj) {

        return (UserService)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获取开始时间
                long start=System.currentTimeMillis();
                method.invoke(obj,null);
                //获取结束时间
                long end=System.currentTimeMillis();
                System.out.println(method.getName()+"方法耗时"+(end-start)/1000+"s");
                return obj;
            }
        });
    }
}

4.测试类


public class MyTest {
    public static void main(String[] args) {
        UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
        userService.getUsers();
        userService.deleteUser();
    }
}

5.测试结果

 以上还可以把代理工具类传递的参数用泛型,那么传递任何东西都可以了。

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1.1 Java语言发展简史2 1.2 认识Java语言3 1.2.1 Java语言特性3 1.2.2 JavaApplet4 1.2.3 丰富的类库4 1.2.4 Java的竞争对手5 1.2.5 Java在应用领域的优势7 1.3 Java平台的体系结构7 1.3.1 JavaSE标准版8 1.3.2 JavaEE企业版10 1.3.3 JavaME微型版11 1.4 JavaSE环境安装和配置12 1.4.1 什么是JDK12 1.4.2 JDK安装目录和实用命令工具介绍12 1.4.3 设置环境变量13 1.4.4 验证配置的正确性14 1.5 MyEcilpse工具介绍JavaSE环境安装和配置15 1.6 本章练习16 第2章 2.1 什么是程序18 2.2 计算机中的程序18 2.3 Java程序19 2.3.1 Java程序中的类型19 2.3.2 Java程序开发三步曲21 2.3.3 开发Java第一个程序21 2.3.4 Java代码中的注释23 2.3.5 常见错误解析24 2.4 Java类库组织结构和文档27 2.5 Java虚拟机简介28 2.6 Java技术两种核心运行机制29 2.7 上机练习30 第3章 3.1 变量32 3.1.1 什么是变量32 3.1.2 为什么需要变量32 3.1.3 变量的声明和赋值33 3.1.4 变量应用实例33 3.2 数据的分类34 3.2.1 Java中的八种基本数据类型34 3.2.2 普及二进制36 3.2.3 进制间转换37 3.2.4 基本数据类型间转换38 3.2.5 数据类型应用实例38 3.2.6 引用数据类型39 3.3 关键字.标识符.常量39 3.3.1 变量命名规范39 3.3.2 经验之谈-常见错误的分析与处理40 3.3.3 Java标识符命名规则41 3.3.4 关键字42 3.3.5 常量42 3.4 运算符43 3.4.1 算术运算符43 3.4.2 赋值操作符45 3.4.3 关系操作符47 3.4.4 逻辑操作符48 3.4.5 位操作符49 3.4.6 移位运算符49 3.4.7 其他操作符50 3.5 表达式52 3.5.1 表达式简介52 3.5.2 表达式的类型和值52 3.5.3 表达式的运算顺序52 3.5.4 优先级和结合性问题52 3.6 选择结构54 3.6.1 顺序语句54 3.6.2 选择条件语句54 3.6.3 switch结构59 3.6.4 经验之谈-常见错误的分析与处理65 3.6.5 Switch和多重if结构比较66 3.7 循环语句66 3.7.1 While循环67 3.7.2 经验之谈-常见while错误70 3.7.3 do-while循环72 3.7.4 for循环74 3.7.5 经验之谈-for常见错误76 3.7.6 循环语句小结78 3.7.7 break语句79 3.7.8 continue语句82 3.8 JavaDebug技术84 3.9 本章练习85 第4章 4.1 一维数组90 4.1.1 为什么要使用数组90 4.1.2 什么是数组91 4.1.3 如何使用数组92 4.1.4 经验之谈-数组常见错误97 4.2 常用算法98 4.2.1 平均值,最大值,最小值98 4.2.3 数组排序102 4.2.3 数组复制103 4.3 多维数组105 4.3.1 二重循环105 4.3.2 控制流程进阶107 4.3.3 二维数组111 4.4 经典算法113 4.4.1 算法-冒泡排序113 4.4.2 插入排序115 4.5 增强for循环116 4.6 本章练习117 第5章 5.1 面向过程的设计思想120 5.2 面向对象的设计思想120 5.3 抽象121 5.3.1 对象的理解121 5.3.2 Java抽象思想的实现122 5.4 封装124 5.4.1 对象封装的概念理解124 5.4.2 类的理解125 5.4.3 Java类模板创建125 5.4.4 Java中对象的创建和使用127 5.5 属性130 5.5.1 属性的定义130 5.5.2 变量131 5.6 方法132 5.6.1 方法的定义132 5.6.2 构造方法135 5.6.4 方法重载138 5.6.5 自定义方法138 5.6.6 系统提供方法139 5.6.7 方法调用140 5.6.8 方法参数及其传递问题144 5.6.9 理解main方法语法及命令行参数147 5.6.1 0递归算法147 5.7 this关键字148 5.8 JavaBean149 5.9 包150 5.9.1 为什么需要包?150 5.9.2 如何创建包151 5.9.3 编译并生成包:151

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值