返回顶部
2 3 4

spring(六)代理模式

6、代理模式

6.1 静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决

  • 真实角色:被代理的角色

  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作

  • 客户:访问代理对象的人

代码步骤:

  • 接口

  • 真实角色

  • 代理角色

  • 客户端访问代理角色

代理模式的好处:

  • 可以使真实角色的操作更加存粹!不用去关注一些公共的业务

  • 公共交给了代理角色,实现了业务的分工

  • 公共业务发生扩展的时候,方便集中管理

j静态代理缺点:

一个真实角色就会产生一个代理角色,代码量会翻倍 开发效率变低

6.2 动态代理

具体参考该条博客理解

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    基于接口:JDK动态代理
    基于类: cglib
    java字节码实现: javasist

需要了解两个类:Proxy:代理 InvocationHandler:调用处理程序

Proxy

java.lang.reflect.Proxy
Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。(大白话:这是一个静态类,类里边有方法得到代理类)

动态代理类 (以下简称为代理类 )是一个实现在类创建时在运行时指定的接口列表的类,具有如下所述的行为。 代理接口是由代理类实现的接口。 代理实例是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序对象,它实现了接口InvocationHandler 。 通过其代理接口之一的代理实例上的方法调用将被分派到实例调用处理程序的invoke方法,传递代理实例, java.lang.reflect.Method被调用方法的java.lang.reflect.Method对象以及包含参数的类型Object Object的数组。 调用处理程序适当地处理编码方法调用,并且返回的结果将作为方法在代理实例上调用的结果返回。

代理类具有以下属性:

  • 代理类是公共的,最终的,而不是抽象的,如果所有代理接口都是公共的。

  • 如果任何代理接口是非公开的,代理类是非公开的,最终的,而不是抽象的 。

  • 代理类的不合格名称未指定。 然而,以字符串"$Proxy"开头的类名空间应该保留给代理类。

  • 一个代理类扩展了java.lang.reflect.Proxy 。

  • 代理类完全按照相同的顺序实现其创建时指定的接口。

  • 如果一个代理类实现一个非公共接口,那么它将被定义在与该接口相同的包中。 否则,代理类的包也是未指定的。 请注意,程序包密封不会阻止在运行时在特定程序包中成功定义代理类,并且类也不会由同一类加载器定义,并且与特定签名者具有相同的包。

  • 由于代理类实现了在其创建时指定的所有接口, getInterfaces在其类对象上调用getInterfaces将返回一个包含相同列表接口的数组(按其创建时指定的顺序),在其类对象上调用getMethods将返回一个数组的方法对象,其中包括这些接口中的所有方法,并调用getMethod将在代理接口中找到可以预期的方法。
    Proxy.isProxyClass方法将返回true,如果它通过代理类 - 由Proxy.getProxyClass返回的类或由Proxy.newProxyInstance返回的对象的类 - 否则为false。

  • 所述java.security.ProtectionDomain代理类的是相同由引导类装载程序装载系统类,如java.lang.Object ,因为是由受信任的系统代码生成代理类的代码。 此保护域通常将被授予java.security.AllPermission 。

  • 每个代理类有一个公共构造一个参数,该接口的实现InvocationHandler ,设置调用处理程序的代理实例。 而不必使用反射API来访问公共构造函数,也可以通过调用Proxy.newProxyInstance方法来创建代理实例,该方法将调用Proxy.getProxyClass的操作与调用处理程序一起调用构造函数

InvocationHandler

InvocationHandler是由代理实例的调用处理程序实现的接口 。
每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
invoke(Object proxy, 方法 method, Object[] args) 处理代理实例上的方法调用并返回结果。

创建代理类工具包:

// 动态代理类
public class StuInvocationHandler<T> implements InvocationHandler {

    // 该代理类持有的对象
    T target;

    public StuInvocationHandler(T target) {
        this.target = target;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     */

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" +method.getName() + "方法");
        //代理过程中插入监测方法,计算该方法耗时
        MonitorUtil.start();
        Object result = method.invoke(target, args);
        MonitorUtil.finish(method.getName());
        return result;
    }
}

时间计时功能工具类

public class MonitorUtil {

    // 计算时间的工具类
    private static ThreadLocal<Long> t1 = new ThreadLocal<>();

    public static void start(){
        t1.set(System.currentTimeMillis());
    }

    // 结束时打印耗时
    public static void finish(String methodName){
        long finishTime = System.currentTimeMillis();
        System.out.println(methodName+"方法耗时"+(finishTime-t1.get())+"ms");
    }

}
posted @ 2021-08-19 16:44  硫没有正七价  阅读(80)  评论(0编辑  收藏  举报