当前位置: 首页 > news >正文

Java 反射与动态代理:实践中的应用与陷阱

Java 反射与动态代理:实践中的应用与陷阱

在现代Java应用中,反射和动态代理提供了强大的灵活性,但它们也带来了性能和复杂度上的挑战。本文将深入探讨这些技术在实际项目中的应用,分析它们可能导致的陷阱,并提供详细的优化策略,尤其在大型系统或基于Spring的项目中,如何避免性能瓶颈和滥用。


一、Java反射的深入应用与陷阱

1. 反射的深入应用:

反射是Java中的一项强大特性,它允许我们在运行时操作类、对象以及方法。反射的灵活性使得它在很多框架和大型系统中都有着广泛的应用,特别是在需要 动态操作类的属性、方法动态加载类 时,反射发挥了重要作用。以下是几个典型的反射应用场景:

(1)框架设计与依赖注入:

反射是许多框架(如Spring、Hibernate)的核心技术之一,尤其在 依赖注入(DI)中,反射被用来动态地实例化类、注入依赖对象。

应用案例: 在Spring框架中,容器启动时会扫描配置的类(如通过@Component注解标注的类),通过反射解析类的构造函数、字段和方法,并通过依赖注入机制将对象的依赖关系建立起来。这个过程几乎完全依赖于反射。

public class MyService {private final DatabaseService databaseService;// 使用反射注入依赖public MyService(DatabaseService databaseService) {this.databaseService = databaseService;}
}

Spring在运行时会通过反射机制查找MyService的构造函数,然后根据配置动态地创建MyService对象,并通过反射将DatabaseService对象注入到它的构造函数中。

(2)插件架构与动态加载:

在构建插件系统时,反射可用于在运行时动态加载、实例化和调用插件类。插件通常遵循特定的接口或约定,反射让我们能够在不改变主程序代码的情况下动态加载插件。

应用案例: 假设我们需要设计一个通用的插件加载器,允许不同的插件在运行时加入系统:

public class PluginLoader {// 动态加载并实例化插件public Object loadPlugin(String className) throws Exception {Class<?> clazz = Class.forName(className);  // 通过反射加载插件类return clazz.getDeclaredConstructor().newInstance();  // 通过反射创建实例}
}

在这个例子中,PluginLoader使用反射动态加载指定的插件类,并创建插件实例。这样做使得系统能够灵活地加载和卸载插件,而不需要修改主程序。

(3)对象序列化与反序列化:

反射广泛用于对象的 序列化和反序列化,例如将对象转为JSON或XML格式时,反射能够动态读取类的字段并构建相应的数据结构。

应用案例: JSON框架(如Gson)使用反射动态读取类字段,然后将这些字段转化为JSON对象:

import com.google.gson.Gson;public class User {private String name;private int age;// 构造函数和getter/setter省略
}public class SerializationExample {public static void main(String[] args) {User user = new User("John", 30);Gson gson = new Gson();// 通过反射将对象转化为JSONString json = gson.toJson(user);System.out.println(json);  // 输出:{"name":"John","age":30}}
}

Gson框架通过反射获取User类的字段并构造JSON字符串。反射使得这一过程变得动态和通用,无需事先为每个类手动编写序列化代码。

2. 反射的陷阱与性能问题:

反射虽然非常灵活,但它也带来了潜在的 性能问题易错性。以下是常见的反射陷阱及示例,帮助开发者更好地理解如何避免这些问题。

(1)性能瓶颈:

反射操作相较于直接的代码调用,通常会有显著的性能开销。这是因为反射涉及 类的查找、类型匹配、方法调用 等操作,通常比直接调用方法更慢。

典型案例: 假设你在一个高并发的系统中,频繁地使用反射调用方法:

public class ReflectionPerformanceTest {public void testMethod() {System.out.println("Test method executed");}public static void main(String[] args) throws Exception {Method method = ReflectionPerformanceTest.class.getMethod("testMethod");long start = System.nanoTime();// 通过反射多次调用方法for (int i = 0; i < 100000; i++) {method.invoke(new ReflectionPerformanceTest());}long end = System.nanoTime();System.out.println("Time taken: " + (end - start) + " nanoseconds");}
}

分析: 在这个例子中,我们使用反射在循环中多次调用testMethod。反射调用的开销每次都增加,尤其是在高并发系统中,这种频繁的反射调用会带来显著的性能瓶颈。

性能影响: 反射会增加:

  • 方法查找:每次调用都需要通过Method.invoke()查找并验证方法。
  • 类型转换:反射过程中需要进行类型转换,增加了CPU负担。

在每秒钟需要执行大量请求的系统中,这种性能损耗是显而易见的。

(2)类型安全问题:

反射绕过了编译时的类型检查,因此容易引发类型不匹配的问题,导致 运行时错误

典型案例: 假设我们在使用反射时没有正确处理方法的参数类型:

public class ReflectionTypeSafety {public void displayMessage(String message) {System.out.println(message);}public static void main(String[] args) throws Exception {Method method = ReflectionTypeSafety.class.getMethod("displayMessage", Object.class);// 错误:将一个Object类型的参数传递给一个期望String类型的参数method.invoke(new ReflectionTypeSafety(), 123);}
}

错误分析: 虽然我们通过反射将displayMessage方法的参数声明为Object.class,但该方法期望的参数类型是String。反射绕过了编译时的类型检查,导致在运行时传入了不匹配的类型,抛出了ClassCastException

陷阱与风险:

  • 反射绕过了Java的 类型安全机制,使得程序更容易引入潜在的类型错误。
  • 运行时错误难以追踪,尤其是当反射调用链较长时,错误更难排查。
(3)反射的代码复杂性:

反射虽然能提供灵活性,但它也使代码变得更加复杂,尤其是在大量依赖反射的系统中,代码的可读性和可维护性都会降低。

典型案例: 在没有反射时,我们通常通过直接调用对象的方法来进行操作。然而,使用反射时,我们需要手动查找方法并设置字段,这可能导致代码冗长且难以理解。

public class ReflectionComplexity {public void displayMessage(String message) {System.out.println(message);}public static void main(String[] args) throws Exception {// 传统的直接调用ReflectionComplexity obj = new ReflectionComplexity();obj.displayMessage("Direct call");// 使用反射进行调用Class<?> clazz = ReflectionComplexity.class;Method method = clazz.getDeclaredMethod("displayMessage", String.class);method.setAccessible(true);  // 需要额外的步骤来处理私有方法method.invoke(obj, "Reflection call");}
}

复杂性分析:

  • 通过反射调用displayMessage方法需要更多的步骤(获取Class对象、查找方法、设置方法可访问性等)。
  • 代码冗长且难以维护,特别是在涉及多个类和复杂的逻辑时。
优化策略:

为了缓解反射带来的性能瓶颈和代码复杂性,以下是几条优化策略:

  1. 缓存反射结果:

    • 对于反射调用中频繁使用的MethodField等结果,可以进行缓存,以避免重复的查找操作。
    public class ReflectionCache {private static Map<String, Method> methodCache = new HashMap<>();public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {String key = clazz.getName() + "." + methodName;if (!methodCache.containsKey(key)) {Method method = clazz.getDeclaredMethod(methodName, parameterTypes);methodCache.put(key, method);}return methodCache.get(key);}
    }
    
  2. 减少反射调用:

    • 在性能关键路径中尽量减少反射调用,避免在循环或高频次调用中使用反射。
    • 可以考虑在应用启动时预先加载并缓存反射结果,尽量避免在每次请求中都进行反射操作。
  3. 考虑替代方案:

    • 如果可能,使用更加 类型安全 的方案,如 接口工厂模式 来替代反射,减少反射的使用范围。

二、动态代理的深入应用与陷阱

1. 动态代理的深入应用

动态代理是Java中一种非常灵活的机制,它允许程序在运行时为接口创建代理对象,并通过代理对象拦截方法调用,注入额外的逻辑。动态代理在框架开发中非常重要,尤其是在实现 AOP(面向切面编程)和 远程方法调用(RPC)等场景中,起到了核心作用。

以下是几种典型的动态代理应用场景和相关实现:


(1)AOP(面向切面编程)中的应用

动态代理是实现AOP的基础,尤其在 Spring AOP 中,动态代理用于拦截方法调用并执行额外逻辑,比如日志记录、事务管理等。

应用案例: 以下是一个简单的AOP示例,展示如何使用JDK动态代理实现方法拦截:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 定义一个接口
interface Service {void performTask();
}// 接口实现类
class ServiceImpl implements Service {@Overridepublic void performTask() {System.out.println("执行任务...");}
}// 动态代理类
class LoggingProxyHandler implements InvocationHandler {private final Object target;public LoggingProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("日志记录: 调用方法 " + method.getName());Object result = method.invoke(target, args); // 调用实际方法System.out.println("日志记录: 方法 " + method.getName() + " 执行完成");return result;}
}public class AopExample {public static void main(String[] args) {// 创建目标对象Service target = new ServiceImpl();// 创建代理对象Service proxy = (Service) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new LoggingProxyHandler(target));// 调用代理方法proxy.performTask();}
}

输出:

日志记录: 调用方法 performTask
执行任务...
日志记录: 方法 performTask 执行完成

分析:

  • 通过Proxy.newProxyInstance()创建了一个动态代理对象。
  • 动态代理拦截了对目标对象的所有方法调用,并在调用前后添加日志逻辑。
  • 这种机制是Spring AOP的基础,用于实现类似事务管理和性能监控的功能。

(2)RPC框架中的应用

在远程方法调用(RPC)场景中,动态代理用于隐藏远程调用的复杂性,开发者只需调用本地代理方法,而代理会在内部处理远程通信逻辑。

应用案例: 以下是一个简化的RPC动态代理实现:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 定义一个远程服务接口
interface RemoteService {String fetchData(String param);
}// 动态代理实现
class RpcProxyHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 模拟发送远程请求System.out.println("发送远程请求: 方法名 " + method.getName() + ",参数 " + args[0]);// 模拟远程返回结果return "远程数据: " + args[0];}
}public class RpcExample {public static void main(String[] args) {// 创建远程服务代理RemoteService proxy = (RemoteService) Proxy.newProxyInstance(RpcExample.class.getClassLoader(),new Class[]{RemoteService.class},new RpcProxyHandler());// 调用代理方法String result = proxy.fetchData("test");System.out.println(result);}
}

输出:

发送远程请求: 方法名 fetchData,参数 test
远程数据: test

分析:

  • 动态代理隐藏了远程通信的细节,开发者只需像调用普通方法一样调用代理对象。
  • RPC框架(如Dubbo、gRPC)通过动态代理实现接口代理,大大简化了远程方法调用的复杂度。

(3)方法拦截与监控

动态代理可以用于性能监控,统计方法调用的时间或参数。例如,在某些监控系统中,我们需要记录所有服务方法的执行耗时。

应用案例:

class MonitoringHandler implements InvocationHandler {private final Object target;public MonitoringHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();Object result = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println("方法 " + method.getName() + " 耗时: " + (endTime - startTime) + " ms");return result;}
}

通过这种方法拦截器,我们可以动态代理任何服务类并统计其方法的执行耗时。


2. 动态代理的陷阱与性能问题

虽然动态代理功能强大,但在实际应用中存在以下陷阱和问题:


(1)性能开销:

动态代理的性能开销主要来自以下两部分:

  1. 反射调用开销: JDK动态代理通过反射调用目标方法(Method.invoke()),相比直接调用方法会慢很多。
  2. 代理链增加复杂性: 如果多个代理对象链式嵌套,每次方法调用都会经过多层代理,进一步增加调用的耗时。

性能测试: 以下代码对比了动态代理和直接调用的性能:

public class ProxyPerformanceTest {public static void main(String[] args) throws Exception {// 目标对象Service target = new ServiceImpl();// 创建动态代理Service proxy = (Service) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new LoggingProxyHandler(target));// 测试直接调用long start = System.nanoTime();for (int i = 0; i < 100000; i++) {target.performTask();}long end = System.nanoTime();System.out.println("直接调用耗时: " + (end - start) + " 纳秒");// 测试代理调用start = System.nanoTime();for (int i = 0; i < 100000; i++) {proxy.performTask();}end = System.nanoTime();System.out.println("代理调用耗时: " + (end - start) + " 纳秒");}
}

结果分析:

  • 直接调用耗时显著低于动态代理。
  • 在高并发或频繁调用场景中,动态代理的性能损耗会被放大。

(2)代理类的复杂性和可维护性

当多个动态代理层嵌套时,代码逻辑变得复杂且难以调试。例如,多个代理链式调用可能导致难以追踪的调用链问题,尤其是在代理方法之间传递参数或处理异常时。


(3)代理对象的类型限制

JDK动态代理要求目标类必须实现接口。如果目标类没有接口,JDK动态代理无法直接使用,必须借助CGLIB等工具来实现。


3. 动态代理的优化策略

为了降低动态代理的性能开销和复杂性,可以采取以下优化策略:


(1)使用CGLIB代理优化性能

JDK动态代理使用反射调用方法,而CGLIB通过生成目标类的子类,直接调用方法(绕过反射),性能更高。

优化示例:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;class CglibProxyExample {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(ServiceImpl.class); // 设置父类enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {System.out.println("日志记录: 调用方法 " + method.getName());Object result = proxy.invokeSuper(obj, args1); // 调用父类方法System.out.println("日志记录: 方法 " + method.getName() + " 执行完成");return result;});ServiceImpl proxy = (ServiceImpl) enhancer.create();proxy.performTask();}
}

(2)减少代理层级

尽量减少代理链层级,可以将多个代理逻辑合并为一个代理类,避免链式调用带来的性能损耗。


(3)在非高频调用中使用代理

动态代理的性能损耗在高频调用场景中较为显著,尽量将代理逻辑应用在初始化阶段或非高频的调用路径中。


三、Spring AOP中的反射与动态代理应用

1. Spring AOP 的核心原理

Spring AOP 是 面向切面编程(Aspect-Oriented Programming) 的一种实现,用于在不修改原始代码的情况下动态增强目标对象的功能。例如,在一个方法执行前后添加日志、权限验证、事务管理等。

Spring AOP 的实现主要基于以下两种动态代理方式:

  1. JDK动态代理: 代理目标对象的接口(要求目标对象实现接口)。
  2. CGLIB代理: 如果目标对象没有实现接口,则使用 CGLIB 生成目标类的子类作为代理。

2. Spring AOP 的反射与动态代理结合

在 Spring AOP 中,动态代理与反射结合,用于拦截目标方法的调用,并注入切面逻辑。以下是具体过程:

  1. 代理对象的生成:
    • 如果目标对象实现了接口,Spring 使用 JDK 动态代理生成代理对象。
    • 如果目标对象没有实现接口,则使用 CGLIB 动态代理。
  2. 拦截方法调用:
    • 代理对象会拦截对目标方法的调用,并通过反射调用切面逻辑和目标方法。
  3. 切面增强:
    • 通过 @Around@Before 等注解定义的切面逻辑会在目标方法执行前后注入。

示例: 以下是一个基于 Spring AOP 的日志记录案例:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;// 定义切面类
@Aspect
@Component
public class LoggingAspect {@Around("execution(* com.example.service.*.*(..))")public Object logMethodCall(ProceedingJoinPoint joinPoint) throws Throwable {String methodName = joinPoint.getSignature().getName();System.out.println("日志记录: 方法 " + methodName + " 开始执行");// 调用目标方法Object result = joinPoint.proceed();System.out.println("日志记录: 方法 " + methodName + " 执行完成");return result;}
}// 目标类
@Component
public class UserService {public void registerUser(String username) {System.out.println("注册用户: " + username);}
}// 测试类
@SpringBootApplication
public class AopTestApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(AopTestApplication.class, args);UserService userService = context.getBean(UserService.class);userService.registerUser("Alice");}
}

输出:

日志记录: 方法 registerUser 开始执行
注册用户: Alice
日志记录: 方法 registerUser 执行完成

分析:

  • Spring AOP 拦截了对 registerUser 方法的调用,在方法执行前后注入了日志逻辑。
  • Spring 通过反射调用目标方法(joinPoint.proceed())以及读取方法的参数和返回值。

3. Spring AOP 中的性能问题

Spring AOP 的灵活性和强大功能是以 动态代理反射调用 为代价的,因此在性能敏感的场景中,可能会出现以下问题:

(1)反射调用的开销

Spring AOP 的 joinPoint.proceed() 本质上是通过反射调用目标方法,反射调用的性能开销比直接调用方法更高,尤其是在高并发或频繁调用的场景中。

(2)代理对象的创建开销
  • JDK 动态代理在创建代理对象时会生成一个实现目标接口的代理类,该过程需要一定的时间和内存。
  • CGLIB 代理需要生成目标类的子类,并通过字节码操作增强功能,其创建成本更高。
(3)嵌套代理带来的性能问题

当一个目标对象被多个切面增强时,会生成多层代理对象。每次方法调用都需要经过多层代理链,这种嵌套会显著增加调用的延迟。

(4)无法代理私有方法

Spring AOP 无法拦截目标对象的私有方法,因为动态代理和 CGLIB 都需要在运行时访问方法签名,而私有方法的访问权限受限。

性能分析测试: 假设我们对一个方法使用多个切面增强,并测试其性能:

@Aspect
@Component
public class TimingAspect {@Around("execution(* com.example.service.*.*(..))")public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();Object result = joinPoint.proceed();long end = System.currentTimeMillis();System.out.println("方法 " + joinPoint.getSignature().getName() + " 耗时: " + (end - start) + " ms");return result;}
}

如果此方法被频繁调用,每次的反射和代理链开销都会累积,对系统性能造成影响。


4. Spring AOP 的优化策略

为了解决 Spring AOP 中的性能问题,可以采取以下优化措施:

(1)合理选择代理类型
  • 优先使用 JDK 动态代理:
    • 如果目标类实现了接口,尽量使用 JDK 动态代理,因为它的代理对象创建成本比 CGLIB 低。
    • Spring 默认会优先使用 JDK 动态代理。
  • 必要时使用 CGLIB:
    • 如果目标类没有实现接口,则只能使用 CGLIB 代理,但需要注意 CGLIB 的性能开销。

强制启用 JDK 动态代理:

application.properties 中设置:

spring.aop.proxy-target-class=false
(2)减少不必要的切面
  • 确保切面只应用于必要的业务逻辑,而不是每个方法。例如,事务管理切面只需要应用在数据库操作相关的服务中。
  • 对切面范围进行限制,比如只拦截特定的包或类。

优化示例: 通过正则表达式限制切面作用范围:

@Around("execution(* com.example.service.UserService.*(..))")
public Object logUserServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable {return joinPoint.proceed();
}
(3)减少代理链层级

将多个切面的逻辑合并到一个切面中,避免多层代理链增加调用延迟。

示例: 将日志记录和性能监控合并到一个切面中:

@Aspect
@Component
public class CombinedAspect {@Around("execution(* com.example.service.*.*(..))")public Object combinedLogic(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();System.out.println("日志记录: 方法 " + joinPoint.getSignature().getName() + " 开始");Object result = joinPoint.proceed();long end = System.currentTimeMillis();System.out.println("日志记录: 方法 " + joinPoint.getSignature().getName() + " 执行完成");System.out.println("方法耗时: " + (end - start) + " ms");return result;}
}
(4)避免过度使用 AOP
  • 如果某些增强逻辑不需要动态性(例如日志),可以通过 显式调用方法工具类 替代 AOP,减少动态代理的使用。

5. CGLIB 代理的局限性与优化
局限性:
  • CGLIB 无法代理 final 类和 final 方法。
  • CGLIB 创建代理对象的成本较高,在高并发场景下可能会影响性能。
优化建议:
  • 避免在 CGLIB 代理的目标类中使用 final 修饰的方法或类。
  • 在需要频繁创建代理对象的场景中,提前加载代理对象并缓存,避免重复创建。

示例: 使用缓存保存代理对象:

public class ProxyCache {private static final Map<Class<?>, Object> proxyCache = new HashMap<>();public static <T> T getProxy(Class<T> clazz, MethodInterceptor interceptor) {return (T) proxyCache.computeIfAbsent(clazz, key -> {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(key);enhancer.setCallback(interceptor);return enhancer.create();});}
}

结论

Spring AOP 的核心在于动态代理与反射的结合,它为开发者提供了灵活的切面编程能力。然而,反射调用和代理对象创建带来的性能开销在高并发场景中会显著放大。通过合理选择代理类型、限制切面范围、合并切面逻辑以及缓存代理对象,可以有效优化 Spring AOP 的性能。理解 AOP 的工作机制和限制,能帮助我们更好地应用这项技术,同时避免滥用带来的隐性问题。


总结

反射与动态代理在Java中提供了强大的灵活性,但在实际应用中,滥用这些特性会导致性能瓶颈和复杂性。通过合理的缓存机制、减少不必要的代理层级、选择合适的代理框架和策略,我们可以有效地减少这些技术带来的负担。在大规模的企业级系统中,尤其是在基于Spring的应用中,合理地使用反射和动态代理,避免陷入性能瓶颈,是开发高效且可维护系统的关键。

相关文章:

Java 反射与动态代理:实践中的应用与陷阱

Java 反射与动态代理&#xff1a;实践中的应用与陷阱 在现代Java应用中&#xff0c;反射和动态代理提供了强大的灵活性&#xff0c;但它们也带来了性能和复杂度上的挑战。本文将深入探讨这些技术在实际项目中的应用&#xff0c;分析它们可能导致的陷阱&#xff0c;并提供详细的…...

tp8读取mysql导出excel

环境&#xff1a;php8.3, thinkphp8.0, mysql8.0 use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\Style\Alignment; use think\facade\Db; use think\response\Json;class Index {public function index…...

【自己动手开发Webpack插件:开启前端构建工具的个性化定制之旅】

在前端开发的世界里&#xff0c;Webpack无疑是构建工具中的“明星”。它强大的功能可以帮助我们高效地打包和管理前端资源。然而&#xff0c;有时候默认的Webpack功能可能无法完全满足我们的特定需求&#xff0c;这时候就需要自定义Webpack插件来大展身手啦&#xff01;今天&am…...

vue2使用flv.js在浏览器打开flv格式视频

组件地址&#xff1a;GitHub - bilibili/flv.js: HTML5 FLV Player flv.js 仅支持 H.264 和 AAC/MP3 编码的 FLV 文件。如果视频文件使用了其他编码格式就打不开。 flv.vue <template><div><el-dialog :visible.sync"innerVisibleFlv" :close-on-pre…...

Spring中的事务管理器TransactionManager

目录 一、主要功能 二、使用场景说明 在Spring框架中&#xff0c;事务管理器&#xff08;TransactionManager&#xff09;是用于管理事务的重要接口。它提供了对事务的全面控制&#xff0c;包括事务的状态管理和资源管理等功能。本文将详细介绍TransactionManager的主要功能、…...

MacOS安装Docker battery-historian

文章目录 需求安装battery-historian实测配置国内源相关文章 需求 分析Android电池耗电情况、唤醒、doze状态等都要用battery-historian&#xff0c; 在 MacOS 上安装 battery-historian&#xff0c;可以使用 Docker 进行安装runcare/battery-historian:latest。装完不需要做任…...

Charles 4.6.7 浏览器网络调试指南:HTTPS抓包(三)

概述 在现代互联网应用中&#xff0c;网络请求和响应是服务交互的核心。对于开发者和测试人员来说&#xff0c;能够准确捕获并分析这些请求&#xff0c;是保证系统稳定性和性能的关键。Charles作为一个强大的网络调试工具&#xff0c;不仅可以捕获普通的HTTP请求&#xff0c;还…...

c++解决常见内存泄漏问题——智能指针的使用及其原理

目录 前言&#xff1a; 1. 智能指针的使用及其原理 1. 1 智能指针的使用场景分析 1.2 RAII和智能指针的设计思路 1.3 C标准库智能指针的使用 1.3 1 auto_ptr 1.3 2 unique_ptr 1.3 3 shared_ptr(重&#xff09; 1.3 4 weak_ptr 1.3 5 模拟实现删除器 2.智能指针的原…...

算法竞赛之离散化技巧 python

目录 离散化实战演练总结 离散化 不改变数据相对大小的情况下&#xff0c;对数据进行相应的下标映射&#xff0c;即离散化。 例如&#xff1a;【100,200,300,400,500】&#xff0c;离散化后为【1,2,3,4,5】 什么时候可以离散化&#xff1a;当数据只与它们之间的相对大小有关&a…...

1.CSS的三大特性

css有三个非常重要的三个特性&#xff1a;层叠性、继承性、优先级 1.1 层叠性 想通选择器给设置想听的样式&#xff0c;此时一个样式就会覆盖&#xff08;层叠&#xff09;另一个冲突的样式。层叠性主要是解决样式冲突的问题。 <!DOCTYPE html> <html lang"en&…...

由于请求的竞态问题,前端仔喜提了一个bug

在平常的开发过程中&#xff0c;你可能会遇到这样一个bug。 测试&#xff1a;我在测一个输入框搜索的功能时&#xff0c;告诉你通过输入框输入的内容&#xff0c;和最终通过输入内容搜索出来的结果对不上。 前端&#xff1a;我是通过调用后端接口拿到的数据&#xff0c;这明显…...

HTML `<head>` 元素详解

在 HTML 文档中&#xff0c;<head> 元素是一个非常重要的部分&#xff0c;它包含了文档的元数据&#xff08;metadata&#xff09;和其他与文档相关的信息。虽然 <head> 中的内容不会直接显示在网页上&#xff0c;但它对网页的行为、样式和搜索引擎优化&#xff08…...

基于RAG构建Text2SQL的实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委,编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。授权多项发明专利。对机器学…...

GPT-4对话模型在客服中的应用与前景:开启智能客服新时代

GPT-4对话模型在客服中的应用与前景:开启智能客服新时代 随着人工智能技术的迅猛发展,基于深度学习的对话模型在各个领域中得到了广泛应用。其中,GPT-4对话模型在客服系统中的应用尤为引人注目。本文将探讨GPT-4在客服中的应用与未来发展前景,并结合具体代码示例进行说明。…...

我想通过python语言,学习数据结构和算法该如何入手?

学习数据结构和算法是编程中的重要基础&#xff0c;Python 是一个非常适合入门的语言。以下是学习数据结构和算法的步骤和建议&#xff1a; 1. 掌握 Python 基础 确保你对 Python 的基本语法、数据类型、控制结构&#xff08;如循环、条件语句&#xff09;、函数等有扎实的理…...

Java多线程的面试面试题及答案解析

什么是进程&#xff1f;什么是线程&#xff1f;有什么区别&#xff1f; 进程是系统资源分配的基本单位&#xff0c;拥有独立的地址空间。线程是 CPU 调度和分派的基本单位&#xff0c;是比进程更小的独立执行的单位&#xff0c;共享所在进程的内存空间等资源。一个进程可以包含…...

python flask中使用or查询和and查询,还有同时使用or、and的情况

在 Flask 中处理数据库查询时&#xff0c;通常会结合使用 ORM 工具&#xff0c;例如 SQLAlchemy。以下是 or 查询、and 查询以及两者同时使用的示例。 文章目录 基础准备1. 使用 or_ 查询2. 使用 and_ 查询3. 同时使用 or_ 和 and_4. 更加复杂的嵌套查询 基础准备 假设有一个…...

C# 解析视频流播放全解析

在多媒体技术日益发达的今天&#xff0c;视频流播放已经成为众多应用中不可或缺的功能。对于开发者而言&#xff0c;掌握如何使用编程语言来解析和播放视频流是一项重要的技能。本文将深入探讨如何使用 C# 来实现视频流的解析与播放。 一、视频流播放原理简介 视频流是将视频…...

关于为什么java中nextInt()和nextLine()不能混用 | nextInt()和nextInt()之类的可以一起用

键盘录入的区别&#xff1a; 第一套体系&#xff1a;遇到空格、制表符、回车都结束&#xff0c;并且都不接收 nextInt()、nextDouble()、next() 遇到空格、制表符、回车就结束&#xff0c;只接收其之前的数据&#xff0c;空格以及空格之后的数据都在缓冲区内&#xff0c;如果…...

计算机图形学:实验一 OpenGL基本绘制

1.OpenGL的环境配置&#xff1a; 集成开发环境Visual Studio Community 2019的安装&#xff1a; 在Windows一栏选择使用C的桌面开发&#xff1b;再转到“单个组件”界面&#xff0c;在“编译器、生成工具和运行时”一栏选择用于“Windows的C CMake工具”&#xff1b;然后转到…...

Node.js 到底是什么

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;它允许开发者使用 JavaScript 编写服务器端代码。 一、主要特点 1. 事件驱动和非阻塞 I/O 模型 Node.js 采用事件驱动架构&#xff0c;通过回调函数处理 I/O 操作&#xff0c;这使得它在处理大量并发请…...

2022年全国职业院校技能大赛网络系统管理赛项模块A:网络构建(样题5)

目录 任务描述 任务清单 (一)基础配置 (二)有线网络配置 (三)无线网络配置 (四)出口网络配置 附录1:拓扑图 附录2:地址规划表 任务描述 随着业务的发展,现在要对海琼银行进行全网改造,为其它区域的网络提供高效的保障服务。同时,海琼银行还针对各个分支行、网点的…...

智慧脚下生根,智能井盖监测终端引领城市安全新革命

在繁忙的都市生活中&#xff0c;我们往往只关注地面的繁华与喧嚣&#xff0c;却忽略了隐藏在地面之下的基础设施——井盖。这些看似不起眼的井盖&#xff0c;实则承担着排水、通讯、电力等重要功能&#xff0c;是城市安全运转的重要一环。然而&#xff0c;传统的井盖管理面临着…...

ES6 简单练习笔记--变量申明

一、ES5 变量定义 1.在全局作用域中 this 其实就是window对象 <script>console.log(window this) </script>输出结果: true 2.在全局作用域中用var定义一个变量其实就相当于在window上定义了一个属性 例如: var name "孙悟空" 其实就相当于执行了 win…...

MsfVenom木马制作及使用

msfvenom基本用法 1、功能介绍 msfvenom的功能&#xff1a;常用于生成木马&#xff0c;在目标机器执行&#xff0c;在本地机器kali中上线&#xff0c;与反弹shell类似。MsfVenom可以生成两种类型的攻击载荷&#xff1a; &#xff08;1&#xff09;Payload&#xff1a;Payloa…...

ChromeOS 132 版本更新

ChromeOS 132 版本更新 1. 企业定制化 Chrome Web Store 管理员现在可以使用新设置定制 Chrome Web Store 以适应他们管理的用户&#xff0c;包括以下功能&#xff1a; 添加公司标志添加首页横幅和自定义公告策划扩展集合实施基于类别的控制 这些设置可以通过管理员控制台进…...

MySQL(表空间)

​开始前先打开此图配合食用 MySQL表空间| ProcessOn免费在线作图,在线流程图,在线思维导图 InnoDB 空间文件中的页面管理 后面也会持续更新&#xff0c;学到新东西会在其中补充。 建议按顺序食用&#xff0c;欢迎批评或者交流&#xff01; 缺什么东西欢迎评论&#xff01;我都…...

智能化加速标准和协议的更新并推动验证IP(VIP)在芯片设计中的更广泛应用

作者&#xff1a;Karthik Gopal, SmartDV Technologies亚洲区总经理 智权半导体科技&#xff08;厦门&#xff09;有限公司总经理 随着AI技术向边缘和端侧设备广泛渗透&#xff0c;芯片设计师不仅需要考虑在其设计中引入加速器&#xff0c;也在考虑采用速度更快和带宽更高的总…...

Chrome远程桌面无法连接怎么解决?

Chrome远程桌面连接已停止工作 Chrome远程桌面是一款极为便捷的浏览器插件&#xff0c;能够帮助用户将自己的计算机连接到其他设备&#xff0c;无论是手机、平板电脑还是其他电脑。然而&#xff0c;在实际使用中&#xff0c;许多用户可能会面临各种各样的问题&#xff0c;比如…...

springcloud alibaba 五大组件

Spring Cloud Alibaba是Spring Cloud的一个子项目&#xff0c;致力于为构建分布式应用提供一站式解决方案。它基于阿里巴巴的底层Java开源框架&#xff0c;主要包含以下五大核心组件&#xff1a; 1. Nacos&#xff08;服务注册与配置中心&#xff09; 功能&#xff1a;Nacos提…...

es 3期 第25节-运用Rollup减少数据存储

#### 1.Elasticsearch是数据库&#xff0c;不是普通的Java应用程序&#xff0c;传统数据库需要的硬件资源同样需要&#xff0c;提升性能最有效的就是升级硬件。 #### 2.Elasticsearch是文档型数据库&#xff0c;不是关系型数据库&#xff0c;不具备严格的ACID事务特性&#xff…...

理解深度学习pytorch框架中的线性层

文章目录 1. 数学角度&#xff1a; y W x b \displaystyle y W\,x b yWxb示例 2. 编程实现角度&#xff1a; y x W T b \displaystyle y x\,W^T b yxWTb3. 常见错误与易混点解析4. 小结参考链接 在神经网络或机器学习的线性层&#xff08;Linear Layer / Fully Connect…...

“上门按摩” 小程序开发项目:基于 SOP 的全流程管理

在竞争激烈的生活服务市场,“上门按摩” 服务需求日益增长。为满足这一需求,我们启动了 O2O 模式的 “上门按摩” 小程序开发项目,该项目涵盖客户端、系统管理端、技师端。以下将通过各类 SOP 对项目进行全面管理,确保项目顺利推进。 一、项目启动 SOP:5W2H 分析法 What(…...

【xcode 16.2】升级xcode后mac端flutter版的sentry报错

sentry_flutter 7.11.0 报错 3 errors in SentryCrashMonitor_CPPException with the errors No type named terminate_handler in namespace std (line 60) and No member named set_terminate in namespace std 替换sentry_flutter版本为&#xff1a; 8.3.0 从而保证oc的…...

Unity自学之旅05

Unity自学之旅05 Unity学习之旅⑤&#x1f4dd; AI基础与敌人行为&#x1f94a; AI导航理论知识&#xff08;基础&#xff09;开始实践 &#x1f383; 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 &#x1f917; 总结归纳 Unity学习之旅⑤ &#x1f4dd; AI基础与敌…...

LINUX下设置分离状态(Detached State)和未设置分离状态的主要区别在于线程资源的管理方式和线程的生命周期。以下是两种状态的对比:

1. 设置分离状态&#xff08;Detached State&#xff09; 资源管理&#xff1a; 线程终止时&#xff0c;系统会自动释放与线程相关的所有资源&#xff08;如线程栈、线程控制块&#xff09;。不需要其他线程显式回收&#xff08;pthread_join&#xff09;。 线程生命周期&…...

软考信安26~大数据安全需求分析与安全保护工程

1、大数据安全威胁与需求分析 1.1、大数据相关概念发展 大数据是指非传统的数据处理工具的数据集,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低等特征。 大数据的种类和来源非常多,包括结构化、半结构化和非结构化数据。 1.2、大数据安全威胁分析 (…...

Alibaba Spring Cloud 一 核心组件、特性

Alibaba Spring Cloud 是 Alibaba 基于 Spring Cloud 的分布式微服务解决方案&#xff0c;提供了一套高性能、高可靠的微服务开发和运维工具。它扩展了 Spring Cloud 的功能&#xff0c;并优化了许多在生产环境中的实践场景&#xff0c;例如服务发现、配置管理、熔断限流等。 …...

通过脚本申请免费SSL证书(泛解析SSL证书)

参考来源 1.https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E 2.https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode 3.https://github.com/acmesh-official/acme.sh/wiki/dnsapi 安装 acme.sh 配置账号 配置默认CA 安装依赖 # Cento…...

基于相机内参推导的透视投影矩阵

基于相机内参推导透视投影矩阵&#xff08;splatam&#xff09;&#xff1a; M c a m [ 2 ⋅ f x w 0.0 ( w − 2 ⋅ c x ) w 0.0 0.0 2 ⋅ f y h ( h − 2 ⋅ c y ) h 0.0 0 0 f a r n e a r n e a r − f a r 2 f a r ⋅ n e a r n e a r − f a r 0.0 0.0 − 1.0 0.0 ] M_…...

代码随想录算法训练营day34

代码随想录算法训练营 —day34 文章目录 代码随想录算法训练营前言一、62.不同路径动态规划动态规划空间优化 二、63. 不同路径 II动态规划动态规划优化空间版 三、343. 整数拆分动态规划贪心算法 96.不同的二叉搜索树总结 前言 今天是算法营的第34天&#xff0c;希望自己能够…...

Orgill EDI需求分析

Orgill 是一家位于美国的家族企业&#xff0c;主要为五金零售商、建材供应商及相关行业提供全面的分销服务和支持&#xff0c;覆盖范围遍及全球。 EDI需求分析 EDI全称Electronic Data Interchange&#xff0c;中文名称是电子数据交换&#xff0c;也被称为“无纸化贸易”。EDI…...

好用的js工具类

格式化相关 // 数字每三位增加一个逗号 function toThousands(num) {if (num) {return num.toString().replace(/\d/, function(n) {// 先提取整数部分return n.replace(/(\d)(?(\d{3})$)/g, function($1) {return $1 ,})})} else {return 0} }//输出10,000 toThousands(10…...

C++ —— 基于范围的 for 循环

C —— 基于范围的 for 循环 语法push_back() 与 emplace_back() 的区别**emplace_back()** 示例代码如下&#xff1a;**push_back()** 示例代码如下&#xff1a; 容器中的元素是结构体和类 语法 C11中引入了基于范围的for循环&#xff0c;语法如下&#xff1a; for (迭代的变…...

15-spring整合mybatis方式一

spring整合mybatis 方式一【重要】 步骤: 1.导入相关jar包 junit mybatis mysql数据库 spring相关的 aop织入 mybatis-spring 【new】 junit junit 4.12 mysql mysql-connector-java 8.0.23 org.mybatis mybatis 3.5.2 org.springframework spring-webmvc 5…...

数据结构:二叉树—面试题(一)

目录 1、相同的树 2、另一棵树的子树 3、翻转二叉树 4、平衡二叉树 5、对称二叉树 6、二叉树遍历 7、二叉树的分层遍历 1、相同的树 习题链接https://leetcode.cn/problems/same-tree/description/https://leetcode.cn/problems/same-tree/description/ 描述&#xff1a…...

GPU算力平台|在GPU算力平台部署可图大模型Kolors的应用实战教程

文章目录 一、GPU算力服务平台GPU算力服务平台的概述 二、平台账号注册流程可图大模型Kolors的应用实战教程可图大模型的介绍可图大模型的应用场景可图大模型Kolors的部署步骤 一、GPU算力服务平台 GPU算力服务平台的概述 蓝耘GPU算力平台专为高性能计算设计&#xff0c;广泛…...

Linux探秘坊-------4.进度条小程序

1.缓冲区 #include <stdio.h> int main() {printf("hello bite!");sleep(2);return 0; }执行此代码后&#xff0c;会 先停顿两秒&#xff0c;再打印出hello bite&#xff0c;但是明明打印在sleep前面&#xff0c;为什么会后打印呢&#xff1f; 因为&#xff…...

Ansys Motor-CAD:IPM 电机实验室 - 扭矩速度曲线

各位电动机迷们&#xff0c;大家好&#xff1a; 在本博客中&#xff0c;我讨论了如何使用 Ansys Motor-CAD 通过 LAB 模块获取扭矩速度曲线。使用每安培最大扭矩电机控制策略&#xff0c;并涵盖恒定扭矩区域和恒定功率、磁通减弱区域。分析了高转子速度如何影响功率输出。 模型…...

关于事件捕获和事件冒泡的理解

我一直对事件捕获和事件冒泡是挺困惑的&#xff0c;好像理解了&#xff0c;但又感觉哪里不对。这篇文章打算深入探讨一些细节性的问题&#xff0c;更好的理解事件捕获和事件冒泡。 当我们点击的时候&#xff0c;浏览器的默认行为是怎么样的&#xff1f; 搞清楚这个非常的重要…...