网站推广的一般方式,广州建筑工程公司有哪些,wordpress密码正确,电子商务主要做什么目录
1. 代理模式简介2. 静态代理3. 动态代理 3.1 JDK动态代理3.2 CGLIB动态代理 4. 面向切面编程(AOP)5. 实战示例6. 总结与最佳实践
1. 代理模式简介
代理模式是一种结构型设计模式#xff0c;它允许我们提供一个代理来控制对其他对象的访问。代理模式在不改变原始类代码…目录
1. 代理模式简介2. 静态代理3. 动态代理 3.1 JDK动态代理3.2 CGLIB动态代理 4. 面向切面编程(AOP)5. 实战示例6. 总结与最佳实践
1. 代理模式简介
代理模式是一种结构型设计模式它允许我们提供一个代理来控制对其他对象的访问。代理模式在不改变原始类代码的情况下通过引入代理类来给原始类附加功能。
代理模式的UML类图 #mermaid-svg-kznD3htVZQLyV9VS {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-kznD3htVZQLyV9VS .error-icon{fill:#552222;}#mermaid-svg-kznD3htVZQLyV9VS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kznD3htVZQLyV9VS .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-kznD3htVZQLyV9VS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kznD3htVZQLyV9VS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kznD3htVZQLyV9VS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kznD3htVZQLyV9VS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kznD3htVZQLyV9VS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kznD3htVZQLyV9VS .marker.cross{stroke:#333333;}#mermaid-svg-kznD3htVZQLyV9VS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kznD3htVZQLyV9VS g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-kznD3htVZQLyV9VS g.classGroup text .title{font-weight:bolder;}#mermaid-svg-kznD3htVZQLyV9VS .nodeLabel,#mermaid-svg-kznD3htVZQLyV9VS .edgeLabel{color:#131300;}#mermaid-svg-kznD3htVZQLyV9VS .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-kznD3htVZQLyV9VS .label text{fill:#131300;}#mermaid-svg-kznD3htVZQLyV9VS .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-kznD3htVZQLyV9VS .classTitle{font-weight:bolder;}#mermaid-svg-kznD3htVZQLyV9VS .node rect,#mermaid-svg-kznD3htVZQLyV9VS .node circle,#mermaid-svg-kznD3htVZQLyV9VS .node ellipse,#mermaid-svg-kznD3htVZQLyV9VS .node polygon,#mermaid-svg-kznD3htVZQLyV9VS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kznD3htVZQLyV9VS .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-kznD3htVZQLyV9VS g.clickable{cursor:pointer;}#mermaid-svg-kznD3htVZQLyV9VS g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-kznD3htVZQLyV9VS g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-kznD3htVZQLyV9VS .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-kznD3htVZQLyV9VS .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-kznD3htVZQLyV9VS .dashed-line{stroke-dasharray:3;}#mermaid-svg-kznD3htVZQLyV9VS #compositionStart,#mermaid-svg-kznD3htVZQLyV9VS .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #compositionEnd,#mermaid-svg-kznD3htVZQLyV9VS .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #dependencyStart,#mermaid-svg-kznD3htVZQLyV9VS .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #dependencyStart,#mermaid-svg-kznD3htVZQLyV9VS .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #extensionStart,#mermaid-svg-kznD3htVZQLyV9VS .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #extensionEnd,#mermaid-svg-kznD3htVZQLyV9VS .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #aggregationStart,#mermaid-svg-kznD3htVZQLyV9VS .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS #aggregationEnd,#mermaid-svg-kznD3htVZQLyV9VS .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-kznD3htVZQLyV9VS .edgeTerminals{font-size:11px;}#mermaid-svg-kznD3htVZQLyV9VS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} «interface» Subject request() RealSubject request() Proxy -realSubject: RealSubject request() 代理模式的主要角色
Subject抽象主题定义代理类和真实主题的共同接口RealSubject真实主题定义代理所代表的真实对象Proxy代理包含对真实主题的引用从而可以操作真实主题
2. 静态代理
静态代理是最简单的代理模式实现方式。代理类在编译时就已经确定在程序运行前就已经存在代理类的 .class 文件。
示例代码
// 抽象主题接口
public interface UserService {void addUser(String username);void deleteUser(String username);
}// 真实主题类
public class UserServiceImpl implements UserService {Overridepublic void addUser(String username) {System.out.println(添加用户: username);}Overridepublic void deleteUser(String username) {System.out.println(删除用户: username);}
}// 静态代理类
public class UserServiceProxy implements UserService {private UserService userService;public UserServiceProxy(UserService userService) {this.userService userService;}Overridepublic void addUser(String username) {System.out.println(开始添加用户...);long startTime System.currentTimeMillis();userService.addUser(username);long endTime System.currentTimeMillis();System.out.println(添加用户完成耗时 (endTime - startTime) ms);}Overridepublic void deleteUser(String username) {System.out.println(开始删除用户...);long startTime System.currentTimeMillis();userService.deleteUser(username);long endTime System.currentTimeMillis();System.out.println(删除用户完成耗时 (endTime - startTime) ms);}
}开始添加用户...
添加用户完成耗时1ms
开始删除用户...
删除用户完成耗时1ms介绍静态代理通过代理类为目标方法添加了额外的功能如记录执行时间并且不需要修改目标类的代码。上述输出表示在添加用户和删除用户时代理类能够控制方法执行并统计耗时。
静态代理的优缺点
优点
可以在不修改目标对象的前提下实现对目标对象的功能扩展实现简单容易理解
缺点
为每个服务都需要创建代理类工作量大不易维护一旦接口增加方法所有代理类都需要修改
3. 动态代理
动态代理是在程序运行时通过反射机制动态创建代理类的代理模式实现方式。
3.1 JDK动态代理
JDK动态代理只能代理实现了接口的类。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 动态代理处理器
public class LogHandler implements InvocationHandler {private Object target;public LogHandler(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(方法执行完成耗时 (endTime - startTime) ms);return result;}// 获取代理对象public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new LogHandler(target));}
}// 使用示例
public class DynamicProxyDemo {public static void main(String[] args) {UserService userService new UserServiceImpl();UserService proxy (UserService) LogHandler.getProxy(userService);proxy.addUser(张三);proxy.deleteUser(张三);}
}开始执行方法addUser
方法执行完成耗时1ms
开始执行方法deleteUser
方法执行完成耗时1ms介绍使用JDK动态代理代理对象的行为由InvocationHandler接口的invoke方法决定。这里我们添加了日志记录功能输出了执行方法的时间统计。
3.2 CGLIB动态代理
CGLIB可以代理没有实现接口的类通过继承被代理类来实现代理。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class CglibProxy implements MethodInterceptor {private Object target;public CglibProxy(Object target) {this.target target;}public Object getProxy() {Enhancer enhancer new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return enhancer.create();}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(开始执行方法 method.getName());long startTime System.currentTimeMillis();Object result proxy.invokeSuper(obj, args);long endTime System.currentTimeMillis();System.out.println(方法执行完成耗时 (endTime - startTime) ms);return result;}
}// 使用示例
public class CglibProxyDemo {public static void main(String[] args) {UserService userService new UserServiceImpl();UserService proxy (UserService) new CglibProxy(userService).getProxy();proxy.addUser(李四);proxy.deleteUser(李四);}
}开始执行方法addUser
方法执行完成耗时1ms
开始执行方法deleteUser
方法执行完成耗时1ms介绍CGLIB动态代理通过继承目标类来生成代理类它不要求目标类实现接口。类似于JDK动态代理这里输出的日志同样记录了方法执行的时间。
4. 面向切面编程(AOP)
AOP是一种编程范式它通过预编译方式和运行期动态代理实现程序功能的统一维护。
Spring AOP示例
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;Aspect
Component
public class LoggingAspect {Around(execution(com.example.service..(..)))public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {long startTime System.currentTimeMillis();Object result joinPoint.proceed();long endTime System.currentTimeMillis();System.out.println(joinPoint.getSignature() 执行耗时 (endTime - startTime) ms);return result;}Before(execution(com.example.service..(..)))public void logBefore() {System.out.println(方法执行前的处理...);}After(execution(com.example.service..(..)))public void logAfter() {System.out.println(方法执行后的处理...);}
}5. 实战示例
下面是一个完整的实战示例展示如何使用代理模式实现方法执行时间统计和日志记录。
// 定义注解
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.METHOD)
public interface LogExecutionTime {
}// 切面类
Aspect
Component
public class MethodExecutionAspect {private static final Logger logger LoggerFactory.getLogger(MethodExecutionAspect.class);Around(annotation(LogExecutionTime))public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {long startTime System.currentTimeMillis();Object result joinPoint.proceed();long endTime System.currentTimeMillis();logger.info(方法 [{}] 执行耗时{}ms,joinPoint.getSignature().getName(), (endTime - startTime));return result;}
}// 使用示例
Service
public class UserServiceImpl implements UserService {LogExecutionTimeOverridepublic void addUser(String username) {// 业务逻辑}
}方法 [addUser] 执行耗时2ms介绍该示例使用了自定义注解LogExecutionTime来标记需要记录执行时间的方法。Spring AOP通过切面对这些方法进行增强输出了方法名称及其执行的耗时。
6. 总结与最佳实践
代理模式是一种非常实用的设计模式它可以帮助我们在不修改原有代码的情况下添加新的功能
静态代理 简单直观但是代理类需要手动编写适用于代理类较少的场景 JDK动态代理 只能代理实现了接口的类运行时动态生成代理类灵活性高 CGLIB动态代理 可以代理未实现接口的类通过继承实现性能较好 Spring AOP 提供了更高层次的抽象支持声明式代理结合了动态代理的优点
使用建议
如果目标类有接口优先使用JDK动态代理如果目标类没有接口使用CGLIB动态代理在Spring框架中优先使用Spring AOP它能自动选择合适的代理方式
注意事项
代理模式会增加系统的复杂度动态代理可能会带来一定的性能开销使用CGLib时注意final方法无法被代理在使用Spring AOP时要注意代理对象的作用域
代理模式是Java开发中非常重要的一个设计模式掌握好它可以帮助我们写出更加优雅和可维护的代码。