男女做那个网站动态图片,怎么制作链接网页,重庆建设施工安全管理网,php网站建设设计方法1. 概念
代理模式#xff08;Proxy Pattern#xff09;是程序设计中的一种结构型设计模式。它为一个对象提供一个代理对象#xff0c;并由代理对象控制对该对象的访问。 2. 原理结构图 抽象角色#xff08;Subject#xff09;#xff1a;这是一个接口或抽象类#xff0…1. 概念
代理模式Proxy Pattern是程序设计中的一种结构型设计模式。它为一个对象提供一个代理对象并由代理对象控制对该对象的访问。 2. 原理结构图 抽象角色Subject这是一个接口或抽象类它声明了代理对象和目标对象共同的接口这样在任何使用目标对象的地方都可以使用代理对象。代理对象和目标对象对外具有一致的方法。真实角色Real Subject也叫被代理角色它实现了抽象角色定义了真实对象在关注的行为中执行的操作。代理角色Proxy也叫委托类它同样实现了抽象角色并持有真实角色的实例可以在调用真实角色前后添加一些操作也可以不调用真实角色而直接返回结果。 3. 代码示例
3.1 示例1静态代理
这个案例涉及到一个银行系统其中有一个 Account 接口一个实现该接口的 SavingsAccount 类以及一个代理类 AccountProxy 来代表 SavingsAccount 对象并添加额外的日志记录功能。
// 定义 Account 接口
interface Account { void deposit(double amount); double withdraw(double amount); double getBalance();
}// 实现 Account 接口的 SavingsAccount 类
class SavingsAccount implements Account { private double balance; public SavingsAccount(double initialBalance) { this.balance initialBalance; } Override public void deposit(double amount) { balance amount; } Override public double withdraw(double amount) { if (amount balance) { balance - amount; return amount; } else { System.out.println(Insufficient balance!); return 0; } } Override public double getBalance() { return balance; }
}// 接着我们创建静态代理类 AccountProxy它实现 Account 接口并持有一个Account类型的引用这里是SavingsAccount对象
class AccountProxy implements Account { private Account account; public AccountProxy(Account account) { this.account account; } Override public void deposit(double amount) { log(Depositing amount); account.deposit(amount); log(Deposited successfully.); } Override public double withdraw(double amount) { log(Withdrawing amount); double withdrawnAmount account.withdraw(amount); if (withdrawnAmount 0) { log(Withdrawn successfully.); } return withdrawnAmount; } Override public double getBalance() { return account.getBalance(); } private void log(String message) { System.out.println([LOG] message); }
}// 在客户端代码中使用 AccountProxy 来代理 SavingsAccount 对象
public class BankClient {public static void main(String[] args) {// 创建SavingsAccount对象Account savingsAccount new SavingsAccount(1000.0);// 使用AccountProxy代理SavingsAccount对象Account proxyAccount new AccountProxy(savingsAccount);// 存款proxyAccount.deposit(500.0);// 取款double withdrawn proxyAccount.withdraw(300.0);System.out.println(withdrawn: withdrawn);// 查询余额double balance proxyAccount.getBalance();System.out.println(Current balance: balance);}
}输出
[LOG] Depositing 500.0
[LOG] Deposited successfully.
[LOG] Withdrawing 300.0
[LOG] Withdrawn successfully.
withdrawn: 300.0
Current balance: 1200.0在这个例子中 AccountProxy 类代理了 SavingsAccount 对象并在每次调用方法时添加了日志记录功能。这种静态代理模式使得可以在不修改原始 SavingsAccount 类的情况下为其添加额外的功能。但是静态代理模式的一个缺点是对于每个需要代理的类都需要手动创建一个代理类这可能导致代码冗余和难以维护。在更复杂的场景中可能会考虑使用动态代理或AOP面向切面编程等更高级的技术来减少代理类的编写工作。 3.2 示例2动态代理
JDK动态代理模式在复杂场景下的一个典型应用是AOP面向切面编程。在这个场景下我们可能会想要在不修改业务逻辑代码的情况下为方法调用添加额外的行为如日志记录、事务管理、安全检查等。下面是一个使用JDK动态代理模式的案例模拟一个具有日志记录和性能监控功能的业务处理系统。
interface BusinessService {void executeBusinessLogic();
}class BusinessServiceImpl implements BusinessService {Overridepublic void executeBusinessLogic() {System.out.println(Executing business logic...);// 模拟业务逻辑执行时间try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println(Business logic executed.);}
}class LoggingDynamicHandler {private Object target;public LoggingDynamicHandler(Object target) {this.target target;}public Object getNewProxyInstance() {// 使用Proxy类的静态方法newProxyInstance来动态创建代理对象return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 方法调用前记录日志System.out.println([LOG] method.getName() is called.);long startTime System.currentTimeMillis();// 调用目标对象的方法Object result method.invoke(target, args);// 方法调用后记录日志和性能信息long endTime System.currentTimeMillis();long elapsedTime endTime - startTime;System.out.println([LOG] method.getName() completed in elapsedTime ms.);return result;}});}
}public class ProxyPatternDemo {public static void main(String[] args) {// 创建目标对象需要被代理的对象BusinessService businessService new BusinessServiceImpl();// 创建LoggingDynamicHandler对象并传入目标对象LoggingDynamicHandler handler new LoggingDynamicHandler(businessService);// 使用LoggingDynamicHandler类的getNewProxyInstance方法获取动态代理对象BusinessService proxyBusinessService (BusinessService) handler.getNewProxyInstance();// 通过代理对象调用方法proxyBusinessService.executeBusinessLogic();}
}将看到如下输出
[LOG] executeBusinessLogic is called.
Executing business logic...
Business logic executed.
[LOG] executeBusinessLogic completed in 1013 ms.在这个例子中当调用proxyBusinessService.executeBusinessLogic()时实际上会调用InvocationHandler的invoke方法并在其中记录日志和计算方法执行的时间。通过这种方式我们可以在不修改BusinessServiceImpl代码的情况下为其添加日志记录和性能监控功能。JDK动态代理模式的优点在于它简单易用只需要目标对象实现接口就可以为其创建代理对象。然而它也有局限性即只能为接口创建代理对象不能为类创建代理对象。如果需要为类创建代理对象可以考虑使用CGLIB等第三方库。 3.3 示例3Cglib代理
添加依赖
dependency groupIdcglib/groupId artifactIdcglib/artifactId version3.3.0/version
/dependency下面是一个CGLIB代理模式的示例假设有一个 UserService 类该类没有实现任何接口想要使用CGLIB来创建其代理对象并在代理对象中添加一些额外的逻辑例如日志记录。
class UserService {public void addUser(String username, String password) {System.out.println(添加用户: username 密码: password);}
}class CglibProxyInterceptor implements MethodInterceptor {private final Object target;public CglibProxyInterceptor(Object target) {this.target target;}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 在方法执行前添加逻辑beforeMethod(method);// 调用目标方法Object result proxy.invokeSuper(obj, args);// 在方法执行后添加逻辑afterMethod(method);return result;}private void beforeMethod(Method method) {System.out.println(开始执行方法: method.getName());// 这里可以添加更多逻辑比如日志记录、权限检查等}private void afterMethod(Method method) {System.out.println(结束执行方法: method.getName());// 这里可以添加更多逻辑比如异常处理、资源清理等}
}class CglibProxyFactory {public static T T createProxy(ClassT clazz, Object target) {Enhancer enhancer new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(new CglibProxyInterceptor(target));return (T) enhancer.create();}
}public class ProxyCglibDemo {public static void main(String[] args) {// 创建一个目标对象UserService userService new UserService();// 使用CGLIB代理工厂创建代理对象UserService proxyUserService CglibProxyFactory.createProxy(UserService.class, userService);// 调用代理对象的方法proxyUserService.addUser(Alice, password123);}
}将看到如下输出
开始执行方法: addUser
添加用户: Alice 密码: password123
结束执行方法: addUser在上面的示例中UserService 类没有实现任何接口但可以使用 CglibProxyFactory 为其创建代理对象。当调用 proxyUserService.addUser() 方法时实际上会触发 CglibProxyInterceptor 中的 intercept 方法可以在这个方法中添加自定义的逻辑。这个示例展示了如何为任意类创建CGLIB代理对象并添加通用代理逻辑。在实际应用中可以根据需要扩展CglibProxyInterceptor类添加更多的自定义逻辑。 4. 优缺点
主要作用 提供对目标对象的间接访问以实现控制、增强或简化原有对象的功能。 优点 降低耦合度代理模式通过引入一个中间层即代理对象来实现对目标对象的访问控制这样可以减少系统各个部分之间的直接依赖从而提高系统的扩展性和维护性。保护目标对象代理可以对目标对象进行封装防止外部对目标对象的直接访问从而起到保护的作用。功能增强代理可以在不改变目标对象的基础上为目标对象添加新的功能比如日志记录、权限检查等。 缺点 性能损耗由于每次调用目标对象的方法都需要先经过代理对象因此可能会带来一定的性能损耗。复杂性增加引入代理模式会增加代码的复杂性需要额外编写代理对象的代码并考虑代理对象与目标对象之间的交互。透明度问题对于不熟悉代理模式的开发者来说可能会觉得代码难以理解和维护因为代理对象的存在增加了代码的间接性。 5. 应用场景
5.1 主要包括以下几个方面
远程代理用于为远程对象提供本地代表。隐藏网络连接和通讯细节让调用者就像访问本地对象一样访问远程服务。安全代理用于控制对敏感对象的访问。可以在代理中加入访问控制逻辑以确保只有满足特定条件的请求才能访问目标对象。智能引用代理用于控制对象的引用计数实现对象的缓存和再利用。常用于缓存框架和对象池中。日志代理用于在不改变原有代码的情况下为目标对象的方法增加日志记录功能。可以记录方法调用的时间、参数、返回值等信息。事务代理用于控制复杂对象的所有事务操作确保所有操作要么全部成功要么全部失败。 5.2 实际应用
在客户端-服务器架构中远程代理可以代表一个远程对象处理网络通信细节使得客户端可以像与本地对象交互一样与远程对象交互。在访问控制系统中安全代理用于控制对敏感资源的访问例如确保用户在访问文件系统或数据库前已经通过身份验证和授权检查。在业务层和服务层之间添加一个代理层用于记录方法调用的详细信息如参数、返回值和执行时间以便于性能监控和故障排查。在企业应用中事务代理可以包装业务操作确保所有操作在一个事务上下文中完成要么全部成功提交要么在出现错误时回滚。… 6. JDK中的使用
AOP面向切面编程 Spring AOP 是 Spring 框架中的一个核心功能它允许开发者定义跨越多个点的横切关注点如安全、事务、缓存等。AOP 在运行时通过动态代理将这些横切关注点织入到目标对象的方法调用前后从而实现对这些方法的增强。Spring AOP 支持两种类型的动态代理基于接口的 JDK 动态代理和基于继承的 CGLib 动态代理。JDK 动态代理要求目标类实现一个或多个接口而 CGLib 动态代理则不要求目标类有接口它通过生成目标类的子类来实现代理。 MyBatis 拦截器Interceptor机制MyBatis允许开发者自定义拦截器来拦截对Mapper接口方法的调用。这种机制也是基于代理模式实现的拦截器可以在方法调用前后添加自定义的逻辑比如修改参数、处理结果或者进行日志记录等。Mapper接口的动态代理在MyBatis中当我们定义了一个Mapper接口和一个对应的XML配置文件后我们并没有实现这个接口但仍然可以调用它的方法来执行数据库操作。这是因为MyBatis使用动态代理来实例化这些Mapper接口。当应用程序尝试获取一个Mapper接口的实例时MyBatis实际上返回的是一个动态生成的代理对象。这个代理对象内部持有一个指向Mapper接口的引用并将接口方法的调用转发到这个内部引用上进而执行相应的SQL语句。 7. 注意事项
明确代理目的代理应明确增强、控制或保护目标对象的目的。确保代理逻辑正确代理类中的代理逻辑应准确无误避免引入新的问题。保持目标对象不变代理模式不应修改目标对象的代码仅通过代理对象进行交互。考虑性能影响代理可能会引入一定的性能开销需权衡利弊。注意线程安全若代理对象在多线程环境下使用需确保线程安全。妥善处理异常代理过程中可能出现的异常应得到妥善处理。选择合适的代理类型根据具体需求选择静态代理、动态代理或虚拟代理等合适的代理类型。 8. 外观模式 VS 代理模式
模式目的模式架构主要角色应用场景外观模式简化接口减少系统的复杂性外观角色和子系统角色复杂的系统且包含多个子系统简化系统的接口代理模式控制对被代理类的访问代理角色和目标角色为其他对象提供一个代理以控制对这个对象的访问装饰者模式为对象动态添加行为或责任而不改变其接口抽象组件和多个具体装饰者适用于需要为对象添加新功能而不改变其接口的场景