架构系列——java动态代理中的InvocationHandler和Proxy,知道这些已经妥妥的了

博主专注于Java、架构、Linux、小程序、爬虫、自动化等技术。 工作期间含泪整理出一些资料,微信搜索【程序员高手之路】,回复 【java】【黑客】【爬虫】【小程序】【面试】等关键字免费获取资料

前言

先赞后看,此生必赚!

Java中动态代理的实现,主要是InvocationHandler和Proxy的使用。

可以通过以下步骤实现一个动态代理:

一、创建正常的接口以及实现类

1. 接口:

public interface People {
    public void working();
}

2. 实现类:

public class Student implements People {
    
    @Override
    public void work() {
        System.out.println("正在学习...");
    }

}

二、创建一个PeopleHandler实现InvocationHandler

public class PeopleHandler implements InvocationHandler {
    private Object obj;
    
    public PeopleHandler(Object obj) {
        this.obj = obj;
    }

    public Object getProxy(Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke...");
        Object result = method.invoke(obj, args);
        System.out.println("after invoke...");
        return result;
    }

}

解读:

PeopleHandler(Object obj):通过被代理对象创建handler;

getProxy(Object obj):通过被代理对象创建代理;

invoke(Object proxy, Method method, Object[] args):代理不直接调用invoke,而是使用正常的方法时都会走invoke方法;

三、调用方法

可以使用两种方式调用方法:

1. 直接调用

不使用代理类直接调用,直接实现业务逻辑

2. 使用代理类调用

使用代理类调用,间接实现业务逻辑

public class TestProxy {
    public static void main(String[] args) {
        //1.直接调用
        System.out.println("直接调用:");
        People people = new Student();
        people.work();
        
        //2.通过代理调用
        System.out.println("
通过代理调用:");
        PeopleHandler handler = new PeopleHandler(people);
        People proxy = (People) handler.getProxy(people);
        proxy.work();
    }
}

结果:

直接调用:
正在学习...

通过代理调用:
before invoke...
正在学习...
after invoke...

四、总结

1. 使用代理的好处

从上面的案例可以看出,两者都可以实现正常的业务逻辑,那为啥要多此一举地使用代理类呢?

1.1 降低耦合度

正常逻辑work()日志的关系没那么强烈,可以对业务逻辑的各个部分进行隔离。

1.2 提高可重用性

如果不使用代理,需要每一次在调用work()前后都要写日志,这样的话,代码的可重用性为0!

使用代理之后,只需要在handler的invoke()方法中写一次即可,重用性明显提高!

2. 使用场景

除了上面案例中的日志,还有性能统计,安全控制,事务处理,异常处理等等。

安全控制举例

校验用户权限,每一个菜单请求,都要判断一下请求的用户是否有该菜单权限。菜单多了,代码冗余,且容易遗漏。

通过动态代理就可以实现为:每一个用户,每一个菜单的请求,都经过代理(proxy),由他判断是否有权限,调用者只需要调用,实现自己的逻辑,不关心权限问题。

原文地址:https://www.cnblogs.com/shuhao66666/p/12925390.html