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

设计模式-代理模式详解

代理模式详解

目录

  • 1. 代理模式简介
  • 2. 核心流程
  • 3. 重难点分析
  • 4. Spring中的源码分析
  • 5. 面试高频点

1. 代理模式简介

1.1 定义

代理模式(Proxy Pattern)是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不改变目标对象的情况下,通过代理对象来增强目标对象的功能。

1.2 核心思想

  • 控制访问:代理对象控制对目标对象的访问
  • 功能增强:在不修改目标对象的前提下,增加额外功能
  • 透明性:客户端通过代理对象访问目标对象,感觉不到代理的存在

1.3 适用场景

  • 远程代理:为远程对象提供本地代表
  • 虚拟代理:创建开销大的对象时使用
  • 安全代理:控制对原始对象的访问权限
  • 智能引用:在访问对象时执行额外的操作
  • 缓存代理:为开销大的运算结果提供临时存储

1.4 代理模式分类

静态代理
// 接口
public interface UserService {void saveUser(String user);
}// 目标对象
public class UserServiceImpl implements UserService {@Overridepublic void saveUser(String user) {System.out.println("保存用户: " + user);}
}// 代理对象
public class UserServiceProxy implements UserService {private UserService userService;public UserServiceProxy(UserService userService) {this.userService = userService;}@Overridepublic void saveUser(String user) {System.out.println("代理前处理");userService.saveUser(user);System.out.println("代理后处理");}
}
动态代理
  • JDK动态代理:基于接口的动态代理
  • CGLIB动态代理:基于继承的动态代理

2. 核心流程

2.1 静态代理流程

客户端代理对象目标对象调用方法前置处理调用目标方法返回结果后置处理返回结果客户端代理对象目标对象

2.2 动态代理流程

JDK动态代理流程
客户端动态代理对象调用处理器目标对象调用方法invoke()前置处理反射调用目标方法返回结果后置处理返回结果返回结果客户端动态代理对象调用处理器目标对象
CGLIB动态代理流程
客户端CGLIB代理对象方法拦截器目标对象调用方法intercept()前置处理调用父类方法返回结果后置处理返回结果返回结果客户端CGLIB代理对象方法拦截器目标对象

2.3 代理模式实现步骤

2.3.1 静态代理实现步骤

步骤1:定义业务接口

// 定义目标对象和代理对象的共同接口
public interface UserService {void saveUser(String user);void deleteUser(String userId);String findUser(String userId);
}

步骤2:实现目标类

// 创建目标对象的具体实现
public class UserServiceImpl implements UserService {@Overridepublic void saveUser(String user) {System.out.println("保存用户: " + user);// 模拟数据库操作try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void deleteUser(String userId) {System.out.println("删除用户: " + userId);}@Overridepublic String findUser(String userId) {System.out.println("查找用户: " + userId);return "用户信息: " + userId;}
}

步骤3:创建静态代理类

// 手动创建代理类,实现相同的接口
public class UserServiceStaticProxy implements UserService {private UserService target; // 目标对象public UserServiceStaticProxy(UserService target) {this.target = target;}@Overridepublic void saveUser(String user) {// 前置处理System.out.println("代理前:开始保存用户");long startTime = System.currentTimeMillis();// 调用目标方法target.saveUser(user);// 后置处理long endTime = System.currentTimeMillis();System.out.println("代理后:保存用户完成,耗时: " + (endTime - startTime) + "ms");}@Overridepublic void deleteUser(String userId) {System.out.println("代理前:开始删除用户");target.deleteUser(userId);System.out.println("代理后:删除用户完成");}@Overridepublic String findUser(String userId) {System.out.println("代理前:开始查找用户");String result = target.findUser(userId);System.out.println("代理后:查找用户完成");return result;}
}

步骤4:客户端调用

public class StaticProxyClient {public static void main(String[] args) {// 创建目标对象UserService target = new UserServiceImpl();// 创建代理对象UserService proxy = new UserServiceStaticProxy(target);// 通过代理对象调用方法proxy.saveUser("张三");proxy.deleteUser("001");String user = proxy.findUser("001");System.out.println("查找结果: " + user);}
}
2.3.2 JDK动态代理实现步骤

步骤1:定义业务接口(同上)

步骤2:实现目标类(同上)

步骤3:创建调用处理器

// 实现InvocationHandler接口
public class UserServiceInvocationHandler implements InvocationHandler {private Object target; // 目标对象public UserServiceInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置处理System.out.println("动态代理前:调用方法 " + method.getName());long startTime = System.currentTimeMillis();// 通过反射调用目标方法Object result = method.invoke(target, args);// 后置处理long endTime = System.currentTimeMillis();System.out.println("动态代理后:方法 " + method.getName() + " 执行完成,耗时: " + (endTime - startTime) + "ms");return result;}
}

步骤4:创建动态代理工厂

// 动态代理工厂类
public class DynamicProxyFactory {public static Object createProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), // 类加载器target.getClass().getInterfaces(),   // 接口数组new UserServiceInvocationHandler(target) // 调用处理器);}// 泛型版本,提供类型安全@SuppressWarnings("unchecked")public static <T> T createProxy(T target, Class<T> interfaceClass) {return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class<?>[]{interfaceClass},new UserServiceInvocationHandler(target));}
}

步骤5:客户端调用

public class DynamicProxyClient {public static void main(String[] args) {// 创建目标对象UserService target = new UserServiceImpl();// 创建动态代理对象UserService proxy = (UserService) DynamicProxyFactory.createProxy(target);// 通过代理对象调用方法proxy.saveUser("李四");proxy.deleteUser("002");String user = proxy.findUser("002");System.out.println("查找结果: " + user);// 使用泛型版本UserService proxy2 = DynamicProxyFactory.createProxy(target, UserService.class);proxy2.saveUser("王五");}
}
2.3.3 CGLIB动态代理实现步骤

步骤1:添加CGLIB依赖

<!-- Maven依赖 -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

步骤2:实现目标类(不需要接口)

// 目标类,不需要实现接口
public class UserServiceCglib {public void saveUser(String user) {System.out.println("CGLIB保存用户: " + user);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}public void deleteUser(String userId) {System.out.println("CGLIB删除用户: " + userId);}public String findUser(String userId) {System.out.println("CGLIB查找用户: " + userId);return "CGLIB用户信息: " + userId;}
}

步骤3:创建方法拦截器

// 实现MethodInterceptor接口
public class UserServiceMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 前置处理System.out.println("CGLIB代理前:调用方法 " + method.getName());long startTime = System.currentTimeMillis();// 调用目标方法(使用MethodProxy,性能更好)Object result = proxy.invokeSuper(obj, args);// 后置处理long endTime = System.currentTimeMillis();System.out.println("CGLIB代理后:方法 " + method.getName() + " 执行完成,耗时: " + (endTime - startTime) + "ms");return result;}
}

步骤4:创建CGLIB代理工厂

// CGLIB代理工厂类
public class CglibProxyFactory {public static Object createProxy(Class<?> targetClass) {// 创建Enhancer对象Enhancer enhancer = new Enhancer();// 设置父类enhancer.setSuperclass(targetClass);// 设置回调enhancer.setCallback(new UserServiceMethodInterceptor());// 创建代理对象return enhancer.create();}// 泛型版本@SuppressWarnings("unchecked")public static <T> T createProxy(Class<T> targetClass, Class<T> interfaceClass) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setInterfaces(new Class<?>[]{interfaceClass});enhancer.setCallback(new UserServiceMethodInterceptor());return (T) enhancer.create();}
}

步骤5:客户端调用

public class CglibProxyClient {public static void main(String[] args) {// 创建CGLIB代理对象UserServiceCglib proxy = (UserServiceCglib) CglibProxyFactory.createProxy(UserServiceCglib.class);// 通过代理对象调用方法proxy.saveUser("赵六");proxy.deleteUser("003");String user = proxy.findUser("003");System.out.println("查找结果: " + user);}
}
2.3.4 通用代理工具类

创建统一的代理工具类

// 通用代理工具类
public class ProxyUtils {/*** 创建代理对象(自动选择代理方式)*/public static Object createProxy(Object target) {if (target.getClass().getInterfaces().length > 0) {// 有接口,使用JDK动态代理return createJdkProxy(target);} else {// 无接口,使用CGLIB动态代理return createCglibProxy(target);}}/*** 创建JDK动态代理*/public static Object createJdkProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return handleMethod(target, method, args);}});}/*** 创建CGLIB动态代理*/public static Object createCglibProxy(Object target) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {return handleMethod(target, method, args);}});return enhancer.create();}/*** 统一的方法处理逻辑*/private static Object handleMethod(Object target, Method method, Object[] args) throws Throwable {System.out.println("代理前:调用方法 " + method.getName());long startTime = System.currentTimeMillis();Object result = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println("代理后:方法 " + method.getName() + " 执行完成,耗时: " + (endTime - startTime) + "ms");return result;}
}

使用通用工具类

public class UniversalProxyClient {public static void main(String[] args) {// 测试有接口的目标对象UserService userService = new UserServiceImpl();UserService userProxy = (UserService) ProxyUtils.createProxy(userService);userProxy.saveUser("通用代理用户");// 测试无接口的目标对象UserServiceCglib userServiceCglib = new UserServiceCglib();UserServiceCglib cglibProxy = (UserServiceCglib) ProxyUtils.createProxy(userServiceCglib);cglibProxy.saveUser("通用代理CGLIB用户");}
}
2.3.5 实现步骤总结
代理类型步骤1步骤2步骤3步骤4步骤5
静态代理定义接口实现目标类手动创建代理类实现代理逻辑客户端调用
JDK动态代理定义接口实现目标类创建InvocationHandler使用Proxy.newProxyInstance客户端调用
CGLIB动态代理无需接口实现目标类创建MethodInterceptor使用Enhancer.create客户端调用

关键要点:

  1. 静态代理:需要手动编写代理类,但性能最好
  2. JDK动态代理:需要接口,使用反射调用
  3. CGLIB动态代理:不需要接口,使用字节码技术
  4. 选择策略:有接口用JDK,无接口用CGLIB,性能要求高用静态代理

3. 重难点分析

3.1 重难点一:动态代理的实现原理

难点分析
  • 字节码生成:动态代理需要在运行时生成字节码
  • 反射机制:需要理解Java反射的工作原理
  • 类加载机制:动态生成的类需要被正确加载
解决方案
// JDK动态代理实现
public class DynamicProxyExample {public static void main(String[] args) {UserService target = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理前处理");Object result = method.invoke(target, args);System.out.println("代理后处理");return result;}});proxy.saveUser("张三");}
}

3.2 重难点二:JDK动态代理 vs CGLIB动态代理

对比分析
特性JDK动态代理CGLIB动态代理
基于接口继承
性能较慢(反射调用)较快(直接调用)
限制必须有接口目标类不能是final
依赖JDK自带需要第三方库
生成方式接口实现子类继承
选择策略
// 选择策略示例
public class ProxyFactory {public static Object createProxy(Object target) {// 如果有接口,使用JDK动态代理if (target.getClass().getInterfaces().length > 0) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MyInvocationHandler(target));} else {// 否则使用CGLIB动态代理Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(new MyMethodInterceptor(target));return enhancer.create();}}
}

3.3 重难点三:代理模式的性能优化

性能问题
  • 反射调用开销:JDK动态代理使用反射,性能较低
  • 字节码生成开销:动态生成类需要时间
  • 内存占用:代理类会占用额外内存
优化策略
// 1. 缓存代理对象
public class ProxyCache {private static final Map<Class<?>, Object> proxyCache = new ConcurrentHashMap<>();public static Object getProxy(Object target) {return proxyCache.computeIfAbsent(target.getClass(), clazz -> createProxy(target));}
}// 2. 使用CGLIB的FastClass机制
public class FastClassExample {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserServiceImpl.class);enhancer.setCallback(new FastClassInterceptor());enhancer.setUseFastClass(true); // 启用FastClassUserService proxy = (UserService) enhancer.create();}
}

4. Spring中的源码分析

4.1 Spring AOP中的代理实现

核心接口分析
// Spring AOP核心接口
public interface AopProxy {Object getProxy();Object getProxy(ClassLoader classLoader);
}// JDK动态代理实现
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {private final AdvisedSupport advised;@Overridepublic Object getProxy() {return getProxy(ClassUtils.getDefaultClassLoader());}@Overridepublic Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}
}
CGLIB动态代理实现
// CGLIB动态代理实现
class CglibAopProxy implements AopProxy, Serializable {private final AdvisedSupport advised;@Overridepublic Object getProxy() {return getProxy(ClassUtils.getDefaultClassLoader());}@Overridepublic Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());}try {Class<?> rootClass = this.advised.getTargetClass();if (rootClass == null) {throw new AopConfigException("Target class cannot be null");}Class<?> proxySuperClass = rootClass;if (ClassUtils.isCglibProxyClass(rootClass)) {proxySuperClass = rootClass.getSuperclass();Class<?>[] additionalInterfaces = rootClass.getInterfaces();for (Class<?> additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// 验证类validateClassIfNecessary(proxySuperClass, classLoader);// 配置CGLIB增强器Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));Callback[] callbacks = getCallbacks(rootClass);Class<?>[] types = new Class<?>[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}enhancer.setCallbacks(callbacks);enhancer.setCallbackTypes(types);return createProxyClassAndInstance(enhancer, callbacks);}catch (CodeGenerationException | IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": " + ex.getMessage(), ex);}catch (Throwable ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}
}

4.2 Spring代理选择策略

DefaultAopProxyFactory源码分析
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}/*** 判断是否没有用户提供的代理接口*/private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {Class<?>[] ifcs = config.getProxiedInterfaces();return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));}
}
代理选择规则
  1. 强制使用CGLIBproxyTargetClass = true
  2. 优化模式optimize = true
  3. 无接口:目标类没有实现接口
  4. 默认策略:有接口使用JDK,无接口使用CGLIB

4.3 Spring AOP执行流程

核心执行流程
// JdkDynamicAopProxy的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Object target = null;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// 处理equals方法return equals(args[0]);}else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// 处理hashCode方法return hashCode();}else if (method.getDeclaringClass() == DecoratingProxy.class) {// 处理DecoratingProxy接口return AopProxyUtils.advisedTarget(this.advised);}Object retVal;if (this.advised.exposeProxy) {// 暴露代理对象到ThreadLocaloldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);// 获取拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {// 没有拦截器,直接调用目标方法Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// 创建方法调用对象,执行拦截器链MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);retVal = invocation.proceed();}// 处理返回值Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isAssignableFrom(targetClass)) {retVal = target;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {AopContext.setCurrentProxy(oldProxy);}}
}

5. 面试高频点

5.1 基础概念类问题

Q1: 什么是代理模式?有哪些类型?

答案要点:

  • 代理模式是一种结构型设计模式
  • 为其他对象提供代理以控制访问
  • 类型:静态代理、动态代理(JDK、CGLIB)
Q2: 静态代理和动态代理的区别?

答案要点:

  • 静态代理:编译时确定,需要手动编写代理类
  • 动态代理:运行时生成,通过反射或字节码技术
  • 性能:静态代理性能更好,动态代理更灵活

5.2 实现原理类问题

Q3: JDK动态代理的实现原理?

答案要点:

// 核心实现步骤
1. 通过Proxy.newProxyInstance()创建代理对象
2. 代理对象实现目标接口
3. 所有方法调用都转发到InvocationHandler.invoke()
4.invoke()方法中通过反射调用目标方法
Q4: CGLIB动态代理的实现原理?

答案要点:

// 核心实现步骤
1. 通过Enhancer创建代理类
2. 代理类继承目标类
3. 重写目标方法,添加拦截逻辑
4. 使用MethodInterceptor处理方法调用

5.3 Spring AOP类问题

Q5: Spring AOP使用哪种代理方式?

答案要点:

  • 默认策略:有接口用JDK,无接口用CGLIB
  • 强制CGLIB:设置 proxyTargetClass = true
  • 选择依据:目标类是否有接口、是否强制使用CGLIB
Q6: Spring AOP的执行流程?

答案要点:

1. 创建代理对象(JdkDynamicAopProxyCglibAopProxy2. 方法调用时进入invoke()方法
3. 获取拦截器链(Advisor链)
4. 创建MethodInvocation对象
5. 执行拦截器链(责任链模式)
6. 调用目标方法
7. 返回结果

5.4 性能优化类问题

Q7: 如何优化动态代理的性能?

答案要点:

  • 缓存代理对象:避免重复创建
  • 使用CGLIB:比JDK动态代理性能更好
  • 减少反射调用:使用FastClass机制
  • 合理使用:避免过度使用代理
Q8: 代理模式有什么缺点?

答案要点:

  • 性能开销:反射调用和字节码生成
  • 内存占用:代理类占用额外内存
  • 调试困难:代理对象增加调试复杂度
  • 限制条件:CGLIB不能代理final类

5.5 实际应用类问题

Q9: 在项目中如何选择代理方式?

答案要点:

// 选择策略
if (有接口 && 不需要强制CGLIB) {使用JDK动态代理;
} else if (无接口 || 强制CGLIB) {使用CGLIB动态代理;
} else if (性能要求极高) {考虑静态代理;
}
Q10: 如何实现一个简单的AOP框架?

答案要点:

// 核心组件
1. 切面定义:@Aspect注解
2. 切点定义:@Pointcut注解
3. 通知定义:@Before@After4. 代理工厂:创建代理对象
5. 拦截器链:执行切面逻辑

5.6 源码分析类问题

Q11: Spring如何选择代理方式?

答案要点:

// DefaultAopProxyFactory.createAopProxy()
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {// 使用CGLIBreturn new ObjenesisCglibAopProxy(config);
} else {// 使用JDK动态代理return new JdkDynamicAopProxy(config);
}
Q12: 代理对象是如何创建的?

答案要点:

  • JDK:通过 Proxy.newProxyInstance()创建
  • CGLIB:通过 Enhancer.create()创建
  • Spring:通过 AopProxyFactory统一创建

总结

代理模式是Java开发中非常重要的设计模式,特别是在Spring AOP中广泛应用。掌握代理模式的原理、实现方式和在Spring中的应用,对于理解AOP机制和提升代码质量具有重要意义。

关键要点

  1. 理解原理:掌握静态代理和动态代理的实现原理
  2. 区分场景:知道什么时候使用哪种代理方式
  3. 性能考虑:了解代理模式的性能影响和优化方法
  4. Spring集成:理解Spring AOP中代理模式的应用
  5. 实际应用:能够在项目中合理使用代理模式

通过深入学习代理模式,可以更好地理解面向切面编程的思想,提升代码的可维护性和扩展性。

http://www.dtcms.com/a/389206.html

相关文章:

  • 怎样让AI图生3D更加高质高效
  • Java 集合框架 Set 接口:实现类的底层数据结构与核心特点
  • 【大模型】使用Qwen-VL大模型进行验证码识别的完整指南
  • 深度学习体系化入门:从理论到实践的完整框架
  • 餐饮行业系统集成分享:OMS 订单数据推送ERP 核算
  • 深入剖析OpenHarmony ClearPlay DRM驱动:从HDI接口到动态加载的完整实现路径
  • [WesternCTF2018]shrine
  • 硬件 - RK3588部分(2) - 原理图 - 最小系统
  • Android进阶之路 - 从 URL Scheme 到 Deep Link 与 App Link
  • MySQL监控Shell脚本实战指南
  • 【Android】Jetpack Media3 如何播放音频文件 实现视频播放器
  • Android 开发 集成 uni 小程序,并实现相互通信
  • 【office】怎么设置第一章二级标题为1.1 1.2 1.3然后第二章为2.1 2.2 2.3这样子
  • JVM的垃圾回收机制(一次完整的GC流程)
  • 拥抱新一代 Web 3D 引擎,Three.js 项目快速升级 Galacean 指南
  • Linux 内核裁剪与功能扩展实验报告
  • Qt QVCandlestickModelMapper详解
  • LeetCode:20.旋转图像
  • 网络协议深度解析:从OSI七层模型到现代互联网通信的技术实战
  • 慈明学校以孝治家阳光家庭教育中心 学以致用践行以孝治家幸福万家
  • 开心实习之 深度学习之多层感知机
  • 前端构造数据格式及表格添加行
  • 深度学习-神经网络(上篇)
  • 【脑电分析系列】第18篇:传统机器学习在EEG中的应用 — SVM、LDA、随机森林等分类器
  • 理解长短期记忆神经网络(LSTM)
  • Kurt-Blender零基础教程:第2章:建模篇——第1节:点线面的选择与控制与十大建模操作
  • 鸿蒙5.0应用开发——V2装饰器@Monitor的使用
  • 八、Java-XML
  • 计算机在医疗领域应用的独特技术问题分析
  • HTB Intentions writeup(SQL二次注入也是注入)