java动态代理详细介绍

java动态代理详细介绍

一. 为什么要使用动态代理

在介绍动态代理之前我们先来介绍一个案列

  1. 创建接口

    public interface UserService {
        void login();
        void delete();
        void query();
    }
    
  2. 实现并重写接口中的方法

    public class UserServiceImpl implements UserService{
        @Override
        public void login() {
            try {
                long start = System.currentTimeMillis();
                System.out.println("登录");
                Thread.sleep(3000);
                long end = System.currentTimeMillis();
                System.out.println("耗时:"+(end-start));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
        @Override
        public void delete() {
            try {
                long start = System.currentTimeMillis();
                System.out.println("删除");
                Thread.sleep(4000);
                long end = System.currentTimeMillis();
                System.out.println("耗时:"+(end-start));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void query() {
            try {
                long start = System.currentTimeMillis();
                System.out.println("查询");
                Thread.sleep(5000);
                long end = System.currentTimeMillis();
                System.out.println("耗时:"+(end-start));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
  3. 创建实现类

    public class TestUserService {
        public static void main(String[] args) {
            UserService userService = new UserServiceImpl();
            userService.login();
            userService.delete();
            userService.query();
        }
    }
    
    

很显然上述我们所写的代码是为了模拟实现登录 , 删除以及查询功能

那么问题来了 , 如果我现在需要增加一个需求 , 也就是计算每次运行消耗的时间 , 那该怎么办呢?

传统的思想是我在每一个功能上添加计算运行时间的方法 , 如下

public void login() {
        long startTime = System.currentTimeMillis();
        try {
            long start = System.currentTimeMillis();
            System.out.println("登录");
            Thread.sleep(3000);
            long end = System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("执行时间为" + (endTime-startTime));

    }

这种方法的确可以实现计算运行时间的功能 , 但是在实际开发中确实不建议的 , 那么就要用到所谓的动态代理来解决问题了

二. 动态代理是如何使用的

1. 使用动态代理的前提

  • 必须有接口,实现类要实现接口(代理通常是基于接口实现的)。
  • 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

2. 如何使用

MyInvocationHandler 类

MyInvocationHandler类实现了InvocationHandler接口,它定义了invoke方法,该方法在代理实例上的方法被调用时会被自动执行。

  • 成员变量private UserServiceImpl userService;,这个变量存储了被代理的UserServiceImpl实例的引用。
  • 构造函数public MyInvocationHandler(UserServiceImpl userService),这个构造函数接收一个UserServiceImpl实例,并将其赋值给成员变量userService
  • invoke 方法:这是InvocationHandler接口必须实现的方法。它接收三个参数:proxy(代理实例的引用,通常不直接使用),method(被调用的方法的Method对象),和args(被调用方法的参数数组)。在invoke方法内部,首先记录当前时间(startTime),然后调用userService实例上的相应方法(通过method.invoke(userService, args)),并记录调用后的时间(endTime)。最后,它计算并打印出方法调用的耗时(endTime - startTime),并返回调用结果。

TestUserService 类

TestUserService类包含了一个测试方法testProxy,用于演示动态代理的使用。

  • 获取实现类对象UserServiceImpl userService = new UserServiceImpl();,这行代码创建了一个UserServiceImpl的实例。

  • 创建proxy对象

    :通过

    Proxy.newProxyInstance
    

    方法创建了一个

    UserService
    

    接口的代理实例。这个方法的参数包括:

    • 类加载器(this.getClass().getClassLoader()),用于加载代理类。
    • 接口数组(这里应该直接使用new Class[]{UserService.class},因为UserServiceImplgetInterfaces()方法可能返回空数组,除非UserServiceImpl确实实现了其他接口,并且这些接口被UserService所继承,这在常规情况下不太可能)。
    • 调用处理器(new MyInvocationHandler(userService)),即MyInvocationHandler的实例,它负责拦截并处理对代理实例的方法调用。
  • 调用实现类中的方法:通过代理实例proxyInstance调用findAllUser方法。实际上,这个调用会被MyInvocationHandlerinvoke方法拦截,invoke方法会调用userServicefindAllUser方法,并打印出方法调用的耗时。然后,它返回调用结果,这个结果被存储在allUser变量中,并最终被打印出来。

1. 获取实现类对象

java复制代码

UserServiceImpl userService = new UserServiceImpl();

这行代码创建了一个UserServiceImpl的实例,这个类实现了UserService接口。这个实例是最终会被代理对象调用的真实对象。

2. 创建proxy对象

UserService proxyInstance = (UserService) Proxy.newProxyInstance(  
    this.getClass().getClassLoader(),  
    userService.getClass().getInterfaces(),  
    new MyInvocationHandler(userService)  
);

这行代码通过Proxy.newProxyInstance方法创建了一个动态代理对象。这个方法需要三个参数:

  • ClassLoader loader:指定代理类的类加载器。这里使用this.getClass().getClassLoader(),意味着代理类将使用与当前类相同的类加载器。
  • Class<?>[] interfaces:指定代理类要实现的接口列表。由于UserServiceImpl是一个具体的类而不是接口,这里应该使用UserService.class.getInterfaces()(如果UserService是一个接口)或者如果UserServiceImpl没有直接实现任何接口,则应该直接传递new Class[]{UserService.class}(假设UserService是接口)。但在这个例子中,如果UserServiceImpl没有直接实现UserService接口(这在Java中是不常见的,因为通常实现类会实现一个或多个接口),那么这行代码会抛出异常。正确的做法是直接传递接口类数组,如new Class[]{UserService.class}
  • InvocationHandler h:指定一个调用处理器,它实现InvocationHandler接口,并包含invoke方法,该方法会在代理实例上的方法被调用时被调用。这里创建了一个MyInvocationHandler的实例,并将userService作为参数传递给它,以便在invoke方法中能够调用userService的方法。

3. 调用实现类中的方法

List<User> allUser = proxyInstance.findAllUser();  
System.out.println(allUser);

这两行代码通过代理对象proxyInstance调用了findAllUser方法。由于proxyInstance是一个代理对象,当调用findAllUser时,实际上会调用MyInvocationHandlerinvoke方法,然后invoke方法再调用userServicefindAllUser方法。这样,就可以在invoke方法中插入任何需要的额外逻辑。

完整代码

class MyInvocationHandler implements InvocationHandler {
    private UserServiceImpl userService;

    public MyInvocationHandler(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Object obj, Object... args
        long startTime = System.currentTimeMillis();
        Object invoke = method.invoke(userService, args);
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);

        return invoke;
    }
}



public class TestUserService {

    @Test
    public void testProxy(){

        // 1. 获取实现类对象
        UserServiceImpl userService = new UserServiceImpl();

        // 2. 创建proxy对象
        /**
         * ClassLoader loader,
         * Class<?>[] interfaces,
         * InvocationHandler h)
         */
        UserService proxyInstance = (UserService) Proxy.newProxyInstance(
                // 类构造器
                this.getClass().getClassLoader(),
                // 实现类所继承的所有接口
                userService.getClass().getInterfaces(),
                // 处理器 -- InvocationHandler
                new MyInvocationHandler(userService)

        );
        // 调用实现类中的方法
        List<User> allUser = proxyInstance.findAllUser();
        System.out.println(allUser);

    }
}
  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攒了一袋星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值