一文搞懂代理模式

article/2025/10/2 9:23:01

代理模式

  • 前言
  • 一、代理模式是什么?
  • 二、静态代理
  • 三、动态代理
    • 1.jdk动态代理(接口代理)
    • 2.cglib动态代理


前言


一、代理模式是什么?

     代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。(为真实对象提供代理,然后供其他对象通过代理访问真实对象)

二、静态代理

    以租房为例,租客找房东租房,然后中间经过房屋中介,以此为背景,它的UML图如下:
静态代理实现类图

可以看出房东类(RentHouse)和代理类(IntermediaryProxy)都实现了租房接口,这就是一个静态代理的前提,那就是真实类和代理类要实现同一个接口,在代理类中实现真实类的方法同时可以进行真实类方法的增强处理,在一个代理类中就可以完成对多个真实对象的注入工作。代码如下:

public interface IRentHouse {void rentHouse();
}
public class RentHouse implements IRentHouse {@Overridepublic void rentHouse() {System.out.println("实现租房");}
}
public class IntermediaryProxy implements IRentHouse {private IRentHouse iRent;public IntermediaryProxy(IRentHouse iRentHouse) {iRent=iRentHouse;}@Overridepublic void rentHouse() {System.out.println("交中介费");iRent.rentHouse();System.out.println("中介负责维修管理");}
}
//client测试类
public class TestStaticProxy {public static void main(String[] args) {//定义租房IRentHouse iRentHouse = new RentHouse();//定义中介IRentHouse intermediaryProxy = new IntermediaryProxy(iRentHouse);//中介租房intermediaryProxy.rentHouse();}
}

三、动态代理

    从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.

动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务,看到这句话,可以容易的联想到动态代理的实现与反射密不可分。
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

1.jdk动态代理(接口代理)

    Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy类,核心方法是

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

jdk动态代理过程中实际上代理的是接口,是因为在创建代理实例的时候,依赖的是java.lang.reflect包中Proxy类的newProxyInstance方法,该方法的生效就恰恰需要这个参数;

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{……}

下面以案例来说明jdk动态代理的完整过程:涉及两套接口及其实现类,一个代理类,以及一个测试类

//接口1
public interface Animal {void wakeup();void sleep();
}//实现类1
public class Cat implements Animal {private String name;public Cat() {}public Cat(String name) {this.name = name;}@Overridepublic void wakeup() {System.out.println("小猫"+name+"早晨醒来啦");}@Overridepublic void sleep() {System.out.println("小猫"+name+"晚上睡觉啦");}
}//实现类2
public class Dog implements Animal {private String name;public Dog() {}public Dog(String name) {this.name = name;}@Overridepublic void wakeup() {System.out.println("小狗"+name+"早晨醒来啦");}@Overridepublic void sleep() {System.out.println("小狗"+name+"晚上睡觉啦");}
}
//接口2
public interface Person {void wakeup();void sleep();
}
//实现类1
public class Student implements Person{private String name;public Student() {}public Student(String name) {this.name = name;}@Overridepublic void wakeup() {System.out.println("学生"+name+"早晨醒来啦");}@Overridepublic void sleep() {System.out.println("学生"+name+"晚上睡觉啦");}
}
//实现类2
public class Doctor implements Person {private String name;public Doctor() {}public Doctor(String name) {this.name = name;}@Overridepublic void wakeup() {System.out.println("医生"+name+"早晨醒来啦");}@Overridepublic void sleep() {System.out.println("医生"+name+"晚上睡觉啦");}
}
//代理类
public class JDKDynamicProxy implements InvocationHandler {private Object bean;public JDKDynamicProxy(Object bean) {this.bean=bean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodname=method.getName();if (methodname.equals("wakeup")){System.out.println("早安~~~");}else if(methodname.equals("sleep")){System.out.println("晚安~~~");}return method.invoke(bean,args);}
}
//测试类public class TestJDKDynamicProxy {public static void main(String[] args) {JDKDynamicProxy proxy = new JDKDynamicProxy(new Student("张三"));//创建代理实例Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);student.wakeup();student.sleep();proxy = new JDKDynamicProxy(new Doctor("王教授"));Person doctor = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);doctor.wakeup();doctor.sleep();proxy = new JDKDynamicProxy(new Dog("旺旺"));Animal dog = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);dog.wakeup();dog.sleep();proxy = new JDKDynamicProxy(new Cat("咪咪"));Animal cat = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);cat.wakeup();cat.sleep();}
}

在执行过程中,为两个接口分别生成了编译以后的虚拟代理类$Proxy0.class 和 $Proxy1.class,下面以接口1的动态代理过程,讲述jdk动态代理的来龙去脉

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.sun.proxy;import com.deer.test.com.deer.vo.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements Person {private static Method m1;private static Method m4;private static Method m2;private static Method m3;private static Method m0;public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final void wakeup() throws  {try {super.h.invoke(this, m4, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String toString() throws  {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void sleep() throws  {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws  {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m4 = Class.forName("com.deer.test.com.deer.vo.Person").getMethod("wakeup");m2 = Class.forName("java.lang.Object").getMethod("toString");m3 = Class.forName("com.deer.test.com.deer.vo.Person").getMethod("sleep");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

整个调用过程如下(省去本人由于自身原因走的弯路,直接说梳理结果):
从测试类中可以看出,一共创建了四个代理实例,然后每个代理实例对应接口的实现类,道理相同,这里只分析Student类的实现过程
流程图

运行结果
总结对比:
1.静态代理中,代理类和真实类实现的是同一个接口,重写同样的方法;jdk动态代理中,代理类和真实类关系不大,代理类实现无侵入式的代码扩展。
2.静态代理中当接口中方法增加的时候,在代理类代码量也会增加,显然是不妥的;jdk动态代理解决了这个问题,当业务增加,代理类的代码不会增加。
3.jdk动态代理实现的是jdk自带InvocationHandler接口,实现了这个接口的类也叫拦截器类,也叫代理类。

2.cglib动态代理

    从上面可以看出,jdk动态代理的前提条件是,要有接口存在,那还有许多场景是没有接口的,这个时候就需要cglib动态代理了,CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
以下案例中所用到的**被代理类**和和上面jdk动态代理一样

cglib动态代理过程中生成的是实现类的子类,cglib是如何凭空创造的实现类的子类的,下面是测试代码

//所需的代理类
public class CglibProxy implements MethodInterceptor {private Enhancer enhancer=new Enhancer();private Object bean;public CglibProxy(Object bean) {this.bean = bean;}public Object getProxy(){//设置需要创建子类的类enhancer.setSuperclass(bean.getClass());enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {String methodName = method.getName();if (methodName.equals("wakeup")){System.out.println("早安~~~");}else if(methodName.equals("sleep")){System.out.println("晚安~~~");}return method.invoke(bean,objects);}
}
//测试类
public class TestCglibProxy {public static void main(String[] args) {//生成虚拟代理类的代码,本来虚拟代理子类是看不见的,//下面这句话的作用就是把执行过程中cglib增强后的class字节码文件System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\aop");CglibProxy proxy = new CglibProxy(new Student("张三"));Student student = (Student) proxy.getProxy();student.wakeup();student.sleep();proxy = new CglibProxy(new Doctor("王教授"));Doctor doctor = (Doctor) proxy.getProxy();doctor.wakeup();doctor.sleep();proxy = new CglibProxy(new Dog("旺旺"));Dog dog = (Dog) proxy.getProxy();dog.wakeup();dog.sleep();proxy = new CglibProxy(new Cat("咪咪"));Cat cat = (Cat) proxy.getProxy();cat.wakeup();cat.sleep();}
}

附上代理Cat类时候,生成的Cat的子类:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Cat$$EnhancerByCGLIB$$8ca2de8b extends Cat implements Factory {private boolean CGLIB$BOUND;public static Object CGLIB$FACTORY_DATA;private static final ThreadLocal CGLIB$THREAD_CALLBACKS;private static final Callback[] CGLIB$STATIC_CALLBACKS;private MethodInterceptor CGLIB$CALLBACK_0;private static Object CGLIB$CALLBACK_FILTER;private static final Method CGLIB$sleep$0$Method;private static final MethodProxy CGLIB$sleep$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$wakeup$1$Method;private static final MethodProxy CGLIB$wakeup$1$Proxy;private static final Method CGLIB$equals$2$Method;private static final MethodProxy CGLIB$equals$2$Proxy;private static final Method CGLIB$toString$3$Method;private static final MethodProxy CGLIB$toString$3$Proxy;private static final Method CGLIB$hashCode$4$Method;private static final MethodProxy CGLIB$hashCode$4$Proxy;private static final Method CGLIB$clone$5$Method;private static final MethodProxy CGLIB$clone$5$Proxy;static void CGLIB$STATICHOOK4() {CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class var0 = Class.forName("com.example.demo.cglibproxy.vo.Cat$$EnhancerByCGLIB$$8ca2de8b");Class var1;Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());CGLIB$equals$2$Method = var10000[0];CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");CGLIB$toString$3$Method = var10000[1];CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");CGLIB$hashCode$4$Method = var10000[2];CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");CGLIB$clone$5$Method = var10000[3];CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");var10000 = ReflectUtils.findMethods(new String[]{"sleep", "()V", "wakeup", "()V"}, (var1 = Class.forName("com.example.demo.cglibproxy.vo.Cat")).getDeclaredMethods());CGLIB$sleep$0$Method = var10000[0];CGLIB$sleep$0$Proxy = MethodProxy.create(var1, var0, "()V", "sleep", "CGLIB$sleep$0");CGLIB$wakeup$1$Method = var10000[1];CGLIB$wakeup$1$Proxy = MethodProxy.create(var1, var0, "()V", "wakeup", "CGLIB$wakeup$1");}final void CGLIB$sleep$0() {super.sleep();}public final void sleep() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$sleep$0$Method, CGLIB$emptyArgs, CGLIB$sleep$0$Proxy);} else {super.sleep();}}final void CGLIB$wakeup$1() {super.wakeup();}public final void wakeup() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$wakeup$1$Method, CGLIB$emptyArgs, CGLIB$wakeup$1$Proxy);} else {super.wakeup();}}final boolean CGLIB$equals$2(Object var1) {return super.equals(var1);}public final boolean equals(Object var1) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);return var2 == null ? false : (Boolean)var2;} else {return super.equals(var1);}}final String CGLIB$toString$3() {return super.toString();}public final String toString() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();}final int CGLIB$hashCode$4() {return super.hashCode();}public final int hashCode() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);return var1 == null ? 0 : ((Number)var1).intValue();} else {return super.hashCode();}}final Object CGLIB$clone$5() throws CloneNotSupportedException {return super.clone();}protected final Object clone() throws CloneNotSupportedException {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();}public static MethodProxy CGLIB$findMethodProxy(Signature var0) {String var10000 = var0.toString();switch(var10000.hashCode()) {case -1385928386:if (var10000.equals("sleep()V")) {return CGLIB$sleep$0$Proxy;}break;case -508378822:if (var10000.equals("clone()Ljava/lang/Object;")) {return CGLIB$clone$5$Proxy;}break;case 391780310:if (var10000.equals("wakeup()V")) {return CGLIB$wakeup$1$Proxy;}break;case 1826985398:if (var10000.equals("equals(Ljava/lang/Object;)Z")) {return CGLIB$equals$2$Proxy;}break;case 1913648695:if (var10000.equals("toString()Ljava/lang/String;")) {return CGLIB$toString$3$Proxy;}break;case 1984935277:if (var10000.equals("hashCode()I")) {return CGLIB$hashCode$4$Proxy;}}return null;}public Cat$$EnhancerByCGLIB$$8ca2de8b() {CGLIB$BIND_CALLBACKS(this);}public Cat$$EnhancerByCGLIB$$8ca2de8b(String var1) {super(var1);CGLIB$BIND_CALLBACKS(this);}public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {CGLIB$STATIC_CALLBACKS = var0;}private static final void CGLIB$BIND_CALLBACKS(Object var0) {Cat$$EnhancerByCGLIB$$8ca2de8b var1 = (Cat$$EnhancerByCGLIB$$8ca2de8b)var0;if (!var1.CGLIB$BOUND) {var1.CGLIB$BOUND = true;Object var10000 = CGLIB$THREAD_CALLBACKS.get();if (var10000 == null) {var10000 = CGLIB$STATIC_CALLBACKS;if (CGLIB$STATIC_CALLBACKS == null) {return;}}var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];}}public Object newInstance(Callback[] var1) {CGLIB$SET_THREAD_CALLBACKS(var1);Cat$$EnhancerByCGLIB$$8ca2de8b var10000 = new Cat$$EnhancerByCGLIB$$8ca2de8b();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Callback var1) {CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});Cat$$EnhancerByCGLIB$$8ca2de8b var10000 = new Cat$$EnhancerByCGLIB$$8ca2de8b();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {CGLIB$SET_THREAD_CALLBACKS(var3);Cat$$EnhancerByCGLIB$$8ca2de8b var10000 = new Cat$$EnhancerByCGLIB$$8ca2de8b;switch(var1.length) {case 0:var10000.<init>();break;case 1:if (var1[0].getName().equals("java.lang.String")) {var10000.<init>((String)var2[0]);break;}throw new IllegalArgumentException("Constructor not found");default:throw new IllegalArgumentException("Constructor not found");}CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Callback getCallback(int var1) {CGLIB$BIND_CALLBACKS(this);MethodInterceptor var10000;switch(var1) {case 0:var10000 = this.CGLIB$CALLBACK_0;break;default:var10000 = null;}return var10000;}public void setCallback(int var1, Callback var2) {switch(var1) {case 0:this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;default:}}public Callback[] getCallbacks() {CGLIB$BIND_CALLBACKS(this);return new Callback[]{this.CGLIB$CALLBACK_0};}public void setCallbacks(Callback[] var1) {this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];}static {CGLIB$STATICHOOK4();}
}

    不难发现,cglib生成的增强子类,比jdk生成的接口代理类默认多实现了clone();而创建这种子类的核心代码就是:

 public Object getProxy(){//设置需要创建子类的类enhancer.setSuperclass(bean.getClass());enhancer.setCallback(this);return enhancer.create();}

该案例下,cglib的代理实现过程如下:
在这里插入图片描述
总结:cglib动态代理和jdk动态代理的区别显而易见,但是实现逻辑差不多,cglib代理类是通过实现MethodInterceptor,重写intercept方法,通过生成被代理类的子类来达到代理增强代码的目的;而Jdk代理是通过实现InvocationHandler,重写invoke方法,通过生成接口的代理类来达到代码增强的目的,所以jdk动态代理的实现需要接口,cglib则不需要,spring5.0以上以及springboot2.0以上默认采用cglib动态来实现AOP。后面将专门介绍AOP以及spring中是如何实现AOP的!不当之处欢迎大家批评并指正!


http://chatgpt.dhexx.cn/article/gDY7iCA6.shtml

相关文章

手机测试耳机音质的软件,耳机音质测试软件有哪些

耳机音质测试软件并不存在&#xff0c;因为耳机的音质对于人来说是主观的&#xff0c;你认为音质好的耳机&#xff0c;有的人却并不认为也很正常&#xff0c;国内外都没有恒定的耳机音质评判标准&#xff0c;大多数人认为音质好的耳机&#xff0c;那么它十有八九实际就是好的。…

软件测试的基本理论与方法

文章目录 前言软件测试基础1. 软件测试的概念2. 软件测试的目的 测试用例1. 测试用例的概念2. 测试用例的分类3. 测试用例的治理4. 测试用例的编制及使用5. 测试需求 软件生命周期1. 问题的定义及规划2. 需求分析3. 软件设计4. 程序编码5. 软件测试6. 运行维护7. 生命周期模型 …

固态硬盘测试软件有哪些,SSD测试软件有哪些?SSD测试软件盘点

在购买了固态硬盘(SSD)后&#xff0c;如果对商家或官方给出的诸如读写速度等关键性数据存在质疑的话&#xff0c;最好的解决方法莫过于通过SSD测试软件来找寻答案。那么&#xff0c;SSD测试软件有哪些&#xff1f;SSD测试软件哪个比较好用呢&#xff1f;针对上述问题&#xff0…

软件工程-软件测试-测试方法

软件工程-测试方法-白盒和黑盒测试 软件工程-软件测试 软件测试方法可以分为静态测试和动态测试。 静态测试 静态测试是指被测试程序不在程序上运行&#xff0c;而是采用人工检测和计算机辅助金泰分析的手段对程序进行检测。 静态测试方法 &#xff08;1&#xff09;人工检…

软件测试方法和技术有哪些?

软件测试方法和技术有哪些&#xff1f;包括软件测试基础、软件测试方法、软件测试流程和规范、单元测试与集成测试、系统测试、验收测试、软件本地化测试、测试自动化及其框架、白盒测试和黑盒测试等。 软件测试方法技术   软件测试方法&#xff1a; 一、等价类测试方法的…

软件测试方法汇总 - 从不同角度分析软件测试方法有哪些

1、从是否关心内部结构来看 &#xff08;1&#xff09;白盒测试&#xff1a;又称为结构测试或逻辑驱动测试&#xff0c;是一种按照程序内部逻辑结构和编码结构&#xff0c;设计测试数据并完成测试的一种测试方法。 &#xff08;2&#xff09;黑盒测试&#xff1a;又称为数据驱…

常见的软件测试方法有,常见的几种软件测试方法都有哪些

随着互联网的不断发展&#xff0c;越来越多的人也都开始学习软件测试的相关技术&#xff0c;而今天我们就一起来了解一下&#xff0c;常见的几种软件测试方法都有哪些。 1、单元测试 单元测试测试的是代码库的单元。 它们直接调用函数或单元&#xff0c;并确保返回正确的结果。…

Dynatrace系列之- 标记常见问题

Dynatrace系列之- 标记常见问题 在大型环境中&#xff0c;系统的某些方面可能会持续触发不必要的警报。这些告警可能来自非关键组件或者是非关键情况下的资源不足的问题。通常这些问题不需要人员响应。 为了减少此类警报并避免发出垃圾告警邮件&#xff0c;Dynatrace AI根因分…

什么是 Dynatrace 里的 Visually Complete 度量标准

Dynatrace 中的 Visually Complete 是一个度量标准&#xff0c;用于测量在加载过程中用户在页面上看到的内容。Visually Complete 指标是当一个用户看到页面上的所有重要元素并且它们正确地渲染时所测量的时间点。这意味着所有可见的文本、图像和视频都已加载并正确显示。该指标…

DevSecOps 团队请避免陷入这些可观测性陷阱

如果您发现难以管理跨越多个云运行不断变化的容器化工作负载的庞大基础架构&#xff0c;那么您并不孤单。 根据 Dynatrace 近期发布的一项研究&#xff0c;超过一半的组织的 DevSecOps 团队在可观测性数据方面感到痛苦。 多云和混合计算设置的兴起&#xff0c;使大部分组织能够…

前端性能分析工具Dyna Trace使用心得(转)

什么是dynatrace ajax “dynatrace ajax 是一个详细的底层追踪工具&#xff0c;它不仅可以显示所有请求和文件在网络中传输的时间&#xff0c;还会记录浏览器render&#xff0c;CPU消耗、JS解析和运行情况等详细的信息&#xff0c;而这些也只是dynatrace ajax的冰山一角。” 为…

使用dynatrace+showslow进行前端性能测试

原文&#xff1a;http://blog.csdn.net/zhangren07/article/details/6883617 1.背景 应用的性能测试与优化目前主要停留在服务器端的反馈&#xff0c;而对于前端性能标准的研究与测试相对比较空白&#xff0c;缺乏统一的标准与工具。众所周知&#xff0c;浏览器html组件的下载…

什么是 Dynatrace 里的 User Action

用户操作是与最终用户界面的交互&#xff0c;涉及对 Web 服务器的调用&#xff0c;这可能有多个嵌套调用。 它是由用户输入&#xff08;例如页面加载、单击或触摸&#xff09;触发的从一个视图到另一个视图的转换。 Web 应用的 User Action 类型&#xff1a; Load actionsXHR …

Ultra Fast Deep Lane Detection with HybridAnchor Driven Ordinal Classification

Abstract 我们将车道检测过程视为一个使用全局特征的锚定驱动的有序分类问题。 首先&#xff0c;我们在一系列混合&#xff08;行和列&#xff09;锚点上用稀疏坐标表示车道。在锚驱动表示的帮助下&#xff0c;我们将车道检测任务重新表述为一个有序分类问题&#xff0c;以得到…

Dynatrace系列之-排除干扰请求

排除干扰请求 Dyatrace监控了所有服务端的请求。当特定请求的性能或者失败率高的时候&#xff0c;Dynatrace将触发告警。然尔不是所有的高并发的请求都是重要的请求&#xff0c;有些慢请求也不需要告警。比如心跳请求。这些不重要的请求可能会干扰整个服务(service)的响应时间…

Web Performance工具 – Dynatrace AJAX Edition

Dynatrace AJAX Edition是我认为最为强大的Web Performance Profile工具。废话不说了,直接上图介绍其主要功能。 先用IE访问你需要profile的网站,例如google,可以点击dynatrace工具栏来启动。这时候dynatrace就开始记录这个网站触发的一切事件。 我简单测试一下,点击googl…

DynamicArray

文章目录 1 DynamicArray设计要点2 继承关系图和接口实现3 代码实现4 代码优化 1 DynamicArray设计要点 类模板 动态确定内部数组空间的大小实现函数返回数组长度构造拷贝和赋值操作 2 继承关系图和接口实现 继承关系图 接口实现 template < typename T > class D…

云途加油站 | 一文读懂 Dynatrace 与 Amazon Lambda 的“双剑合璧心法”

Amazon Lambda 正在掀起企业级云市场的一场小潮流。不少业内人士发现&#xff0c;越来越多的企业正在将 Lambda 函数加入其技术栈中。 这一潮流其实不难理解—— 一则&#xff0c;门槛低。Amazon Lambda为企业进入云计算提供了相对较低的门槛&#xff0c;无需立即全面推行转移…

Dynatrace AppMon最佳实践(一)

经常有客户问我,如何利用Dynatrace捕获必要的应用性能监控信息,从而快速诊断性能问题?所谓捕获必要的信息,即是在应用出现性能下降的时候,PurePath能够捕获导致事务响应缓慢的方法,或是导致事务失败的异常栈信息,亦或是用户请求的上下文参数。如何通过Dynatrace捕获必要…

什么是 Dynatrace 的 Speed Index 度量标准

Dynatrace 中的 Speed Index 是一种度量网页加载速度的标准&#xff0c;它与 Visually Complete 类似&#xff0c;但更加精细。Speed Index 是一个计算值&#xff0c;反映了整个页面的加载速度&#xff0c;并将所有重要元素的渲染时间考虑在内。与 Visually Complete 不同的是&…