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

一、概念

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

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

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

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

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

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

代理模式--JDK动态代理案例_第1张图片

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

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动态代理案例_第2张图片

 三、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.测试结果

代理模式--JDK动态代理案例_第3张图片

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

你可能感兴趣的:(java)