静态代理模式

一、为什么要有代理模式?

举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。

通过代理,我可以省去很多的时间和精力,把找车子的任务让代理去帮我找。

同理,实际代码设计当中也会有这样的问题:
某一个业务类或者几个业务类都需要实现自己独立的业务,但又要求他们都有输出日志、权限校验等等和实际业务不相关的工作,这极大浪费了资源,同时使得各个业务类之间高度耦合。

代理模式: 代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。

代理模式有以下优点

  • 职责清晰: 让各个业务逻辑只需要关注自己的本职事务,其他诸如日志输出、权限校验、预处理消息、过滤消息等工作后期通过代理来完成
  • 高扩展性: 符合开闭原则,具体主题角色随时会发生变化,但是只要实现了接口,接口不变,代理类就可以不做任何修改继续使用

二、静态代理模式

静态代理,主要涉及三个对象:

  • 抽象主体类:以Phone为例,所有具体主体和代理都实现该接口
  • 具体主体类:以Apple为例
  • 代理类:ProxyPhone
    静态代理类图

新建Phone接口

public interface Phone {

    void buyPhone();
}

实现Apple业务类

public class Apple implements Phone{

    @Override
    public void buyPhone() {
        System.out.println("买苹果手机");
    }

}

创建代理类ProxyPhone

public class ProxyPhone implements Phone {


    private Phone phone;

    ProxyPhone() {
        this.phone = new ProxyPhone();
    }

    ProxyPhone(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void buyPhone() {
        System.out.println("执行之前做的事情");
        this.phone.buyPhone();
        System.out.println("执行之后做的事情");
    }

    public Phone getPhone() {
        return phone;
    }

    public void setPhone(Phone phone) {
        this.phone = phone;
    }
}

测试

public class ProxyTest {
    public static void main(String[] args) {
        ProxyPhone proxyPhone = new ProxyPhone(new Apple());
        proxyPhone.buyPhone();
    }
}

结果如下:

执行之前做的事情
买苹果手机
执行之后做的事情

通过静态代理,在不修改业务类的情况下,可以在业务类执行之前和执行之后,进行相关行为,减少了类的耦合。

当然,缺点也很明显:

  • 代理类和委托类实现了相同的接口,并且也实现了相同的方法,这样就出现了大量的代码重复,如果又产生了一个新的方法,那代理类又需要再实现这个方法,增加了代码维护的复杂度
  • 代理类只服务于一种类型对象,如果要实现服务多类型对象,势必需要为每一种对象都进行代理,程序规模变大,业务类型变多,静态代理就无法实现了。

三、JDK动态代理

通过上面静态代理的案例可以发现–每个代理类都只能为一个接口服务,这样程序开发中会产生很多代理类,维护起来很困难。那有没有一种代理类,可以代理所有实现业务的接口呢?

这就需要使用动态代理,学习动态代理,首先要掌握
java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类。

InvocationHandler

里面只包含一个接口方法
public Object invoke(Object proxy, Method method, Object[] args)

  • Object proxy:被代理对象
  • Method method:要调用的方法
  • Object[] args:调用方法所需要的参数
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

java.lang.reflect.Proxy类

主要使用到Proxy类的newProxyInstance方法

  • ClassLoader loader:类加载器,通过反射拿到
  • Class<?>[] interfaces:类的全部接口
  • InvocationHandler:得到InvocationHandler子例的实例
public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,InvocationHandler h)
  • 注意:动态代理类,只能代理接口,不能代理实例;并且代理类都需要实现InvocationHandler接口,实现Invoke方法,invoke方法就是调用被代理接口的所有方法时需要调用的,返回的值是被代理接口的一个实现类。

以上Phone接口和Apple业务类不再重新写

创建ProxyHandler实现InvocationHandler接口

public class ProxyHandler implements InvocationHandler {
    // 目标对象
    private Object object;

    /**
     * 该方法用于未指定类状态奇、一组接口及调用处理器生成动态代理类实例。
     */
    public Object newInstance(Object object) {
        this.object = object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(), this);
    }

    /**
     * 关联这个实现类的方法被调用时将被执行
     * @param proxy 代理类
     * @param method 原对象被调用的方法
     * @param args 方法村塾
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理--对象方法调用前的逻辑");
        // 调用目标方法
        Object invoke = method.invoke(this.object, args);
        System.out.println("动态代理--对象方法调用后的逻辑");
        return invoke;
    }
}

测试

public class dynamicTest {
    public static void main(String[] args) {
        ProxyHandler proxyHandler = new ProxyHandler();
        Phone apple = (Phone) proxyHandler.newInstance(new Apple());
        apple.buyPhone();
    }
}

结果:

动态代理--对象方法调用前的逻辑
买苹果手机
动态代理--对象方法调用后的逻辑

缺点

通过实现InvocationHandler接口和Proxy类实现动态代理的方法,可以根据实际传入的业务类实现对不同类的代理,但还是有个问题,就是这个动态代理一定要实现InvocationHandler接口才可以使用,对普通的类不可以使用。

四、cglib动态代理

假如我这时候有一个类,不继承自任何接口,也就无法实现invocationHandler接口通过JDK动态代理的方法实现代理。

那这时候,就需要使用cglib动态代理,主要分为以下3步:

  • 引入cglib依赖
  • 实现MethodInterceptor接口中的intercept方法
  • 使用Enhancer实现动态代理

引入cglib依赖

<dependencies>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.1</version>
        </dependency>
    </dependencies>

创建一个没有实现接口的对象

public class Huawei {

    public void makeHuawei() {
        System.out.println("华为,中国自主研发");
    }
}

实现MethodInterceptor接口中的intercept方法

public class MethodHandler implements MethodInterceptor {
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行之前做的事情--cglib代理");
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("执行之后做的事情--cglib代理");
        return object;
    }
}

使用Enhancer实现动态代理


public class CglibTest {

    public static void main(String[] args) {
        // 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置目标类的字节码文件
        enhancer.setSuperclass(Huawei.class);
        // 设置回调函数
        enhancer.setCallback(new MethodHandler());

        // 正式创建代理
        Huawei huawei = (Huawei) enhancer.create();

        huawei.makeHuawei();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值