java基础之动态代理

73 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情

一、代理的介绍

简单来说,动态代理就是在程序运行期,创建目标对象的代理对象,对目标对象中的方法进行功能性增强的一种技术。可以看到,概念种出现了这么几种角色:①.真实角色,②.代理角色,③.方法,④.客户(访问角色)。那么访问角色本可以直接访问真实角色的某个方法,为什么在开发的过程种需要一个代理角色呢?也就说动态代理解决了什么问题。在这里我们明确一个核心概念:动态代理能够让真实对象专注于自己的核心功能,让代理对象拦截客户对真实对象的访问,另外可以在不修改方法源码的情况下,增强被代理对象的方法的功能。

举个例子,小明(真实角色)的主要业务是唱歌,在还没火的时候自己跑东跑西去街头、酒吧等地方唱歌,在这期间需要自己负责找合适的场地,以及和酒吧老板谈工资等业务,突然有一天他火了,很多人要请他唱歌,所有的事亲历亲为他根本忙不过来,这个时候经纪人(代理角色)出现了,客户们要请小明唱歌,不能直接找到小明了,而是需要和经纪人谈,经纪人在商业等方面的理解比小明强(对代理对象的方法增强)。这样小明就可以专注于自己的唱歌业务了,经纪人的存在就是拦截了客户对小明(真实对象)的访问。

二、代理的创建,使用演示

定义明星类

public class BigStar {

    String name;

    public BigStar(String name) {
        this.name = name;
    }

    public String sing(String name) {
        System.out.println(this.name + "正在唱" + this.name);
        return "thanks,thanks";
    }

    public void dance() {
        System.out.println(this.name + "跳舞");
        
    }
}

创建明星接口

public interface Star {

    String sing(String name);

    void dance();

}

创建代理工具类

public class ProxyUtil {

    public static Star createProxy(BigStar bigStar) {
        /**
         * newProxyInstance (ClassLoader loader,
         *              Class<?>[] interfaces,
         *              InvocationHandler h)
         *              参数1 : 用于指定一个类加载器
         *              参数2 : 指定生成代理长什么样子,也就是有哪些方法
         *              参数3 : 用来指定生成的代理做什么事情
         */
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override // 回调方法
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 代理对象要做的事情,会在此处实现
                        if (method.getName().equals("sing")) {
                            System.out.println("准备话筒");
                        } else if (method.getName().equals("dance")) {
                            System.out.println("搭建舞台");
                        }
                        return method.invoke(bigStar, args);
                    }
                }
        );
        return starProxy;
    }
}

测试

public class Test {
    public static void main(String[] args) {
        BigStar s = new BigStar("杨超越");
        // 创建代理对象
        Star proxy = ProxyUtil.createProxy(s);
        // 执行代理方法
        String result = proxy.sing("匆匆那年");
        System.out.println(result);
    }
}

image-20221221130813980

三、动态代理的实际应用

增强接口性能。减少重复工作

public interface UserService {

    void login(String loginName, String passWord) throws Exception;

    void deleteUsers() throws Exception;

    String[] selectUsers() throws Exception;

}

接口优化前

public class UserServiceImpl implements UserService{
    @Override
    public void login(String loginName, String passWord) throws Exception {
        long startTime = System.currentTimeMillis();

        if ("admin".equals(loginName) && "123456".equals(passWord)) {
            System.out.println("登陆成功");
        } else {
            System.out.println("登陆失败");
        }
        Thread.sleep(1000);
        long endTime = System.currentTimeMillis();
        System.out.println("login方法执行耗时:" + (endTime - startTime) / 1000.0 + "s");
    }

    @Override
    public void deleteUsers() throws Exception {
        long startTime = System.currentTimeMillis();

        System.out.println("删除成功");
        Thread.sleep(1000);
        long endTime = System.currentTimeMillis();
        System.out.println("deleteUser方法执行耗时:" + (endTime - startTime) / 1000.0 + "s");
    }

    @Override
    public String[] selectUsers() throws Exception {
        long startTime = System.currentTimeMillis();
        System.out.println("查询出三个用户");
        String[] names = {"odin", "jack", "mouse"};
        Thread.sleep(1000);
        long endTime = System.currentTimeMillis();
        System.out.println("selectUser方法执行耗时:" + (endTime - startTime) / 1000.0 + "s");
        return names;
    }
}

接口实现优化后

public class UserServiceImpl implements UserService{
    @Override
    public void login(String loginName, String passWord) throws Exception {
        if ("admin".equals(loginName) && "123456".equals(passWord)) {
            System.out.println("登陆成功");
        } else {
            System.out.println("登陆失败");
        }
        Thread.sleep(1000);
    }

    @Override
    public void deleteUsers() throws Exception {

        System.out.println("删除成功");
        Thread.sleep(1000);
    }

    @Override
    public String[] selectUsers() throws Exception {
        System.out.println("查询出三个用户");
        String[] names = {"odin", "jack", "mouse"};
        Thread.sleep(1000);
        return names;
    }
}

使用代理增强功能,类似AOP

public class ProxyUtil {

    public static UserService createProxy(UserService userService) {
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{UserService.class}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("login") || method.getName().equals("deleteUsers") || method.getName().equals("selectUsers")) {
                            long startTime = System.currentTimeMillis();

                            Object res = method.invoke(userService, args);

                            long endTime = System.currentTimeMillis();
                            System.out.println(method.getName() + "方法执行耗时 : " + (endTime - startTime) / 1000.0 + "s");
                            return res;
                        } else {
                            Object res = method.invoke(userService, args);
                            return res;
                        }
                    }
                });
        return userServiceProxy;
    }
}

测试类

public class Test {
    public static void main(String[] args) throws Exception {

        UserService userService = ProxyUtil.createProxy(new UserServiceImpl());

        userService.login("admin", "123456");
        System.out.println("=========================================");

        userService.deleteUsers();
        System.out.println("=========================================");

        String[] names = userService.selectUsers();
        System.out.println("查询到用户名:" + Arrays.toString(names));
        System.out.println("=========================================");
    }
}

image-20221221131805972