热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析动态代理模式:23种设计模式之三

在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。
### 引言

在设计模式系列文章中,我们已经探讨了静态代理模式。接下来,我们将深入研究更为灵活和强大的动态代理模式。动态代理模式允许我们在运行时动态生成代理对象,并且可以在不修改原始代码的情况下对方法调用进行拦截和增强。

#### 动态代理的核心概念

动态代理的关键在于能够在程序运行时创建代理对象,而不是在编译时确定。通过使用Java的`java.lang.reflect.Proxy`类和`InvocationHandler`接口,我们可以实现这一目标。

##### 抽象接口

首先定义一个抽象接口,该接口声明了所有需要被代理的方法。例如:

```java
package com.yemaozi.proxy.dynamic;

public interface IGamePlayer {
void login(String username, String password);
void killBoss();
void upGrade();
}
```

##### 真实主题类

接下来,实现上述接口的具体类,即真实主题类。这个类包含了业务逻辑的具体实现:

```java
package com.yemaozi.proxy.dynamic;

public class GamePlayer implements IGamePlayer {
private String name;

public GamePlayer(String name) {
this.name = name;
}

@Override
public void login(String username, String password) {
System.out.println("登录名为 " + username + " 进入游戏," + name + " 登录成功!");
}

@Override
public void killBoss() {
System.out.println(this.name + " 击杀了Boss!");
}

@Override
public void upGrade() {
System.out.println(this.name + " 升级了!");
}
}
```

##### 动态代理处理器

为了实现动态代理,我们需要创建一个实现了`InvocationHandler`接口的类。这个类负责处理所有代理对象的方法调用。

```java
package com.yemaozi.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class GamePlayerInvocationHandler implements InvocationHandler {
private Object obj;

public GamePlayerInvocationHandler(Object obj) {
this.obj = obj;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("login".equalsIgnoreCase(method.getName())) {
System.out.println("代理登录游戏!");
}
return method.invoke(this.obj, args);
}
}
```

##### 动态代理场景类

最后,我们可以通过`Proxy.newProxyInstance`方法来动态创建代理对象,并调用其方法。

```java
package com.yemaozi.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
IGamePlayer gp = new GamePlayer("张三");
InvocationHandler gpHandler = new GamePlayerInvocationHandler(gp);
ClassLoader classLoader = gp.getClass().getClassLoader();
Class[] cls = new Class[]{IGamePlayer.class};
IGamePlayer proxyGp = (IGamePlayer) Proxy.newProxyInstance(classLoader, cls, gpHandler);
proxyGp.login("zhangsan", "123456");
proxyGp.killBoss();
proxyGp.upGrade();
}
}
```

#### 执行结果

```
代理登录游戏!
登录名为 zhangsan 进入游戏,张三 登录成功!
张三 击杀了Boss!
张三升级了!
```

#### 面向切面编程(AOP)

在动态代理模式中,除了动态生成代理对象外,还可以通过面向切面编程(AOP)的思想,在方法调用前后添加额外的功能。例如,可以在方法执行前添加日志记录、权限验证等操作。

##### AOP示例

下面是一个简单的AOP示例,展示了如何在方法调用前后添加前置通知和后置通知。

```java
package com.yemaozi.proxy.dynamic_aop;

public interface Subject {
void doSomething(String str);
}

public class RealSubject implements Subject {
@Override
public void doSomething(String str) {
System.out.println("do something..." + str);
}
}

public interface IAdvice {
void exec();
}

public class BeforeAdvice implements IAdvice {
@Override
public void exec() {
System.out.println("前置通知被执行!");
}
}

public class AfterAdvice implements IAdvice {
@Override
public void exec() {
System.out.println("后置通知被执行!");
}
}

public class MyInvocationHandler implements InvocationHandler {
private Subject realSubject;

public MyInvocationHandler(Subject realSubject) {
this.realSubject = realSubject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
IAdvice beforeAdvice = new BeforeAdvice();
beforeAdvice.exec();
Object result = method.invoke(this.realSubject, args);
IAdvice afterAdvice = new AfterAdvice();
afterAdvice.exec();
return result;
}
}

public class DynamicProxy {
public static T newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler handler) {
@SuppressWarnings("unchecked")
T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
return t;
}
}

public class AOPClient {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new MyInvocationHandler(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Class[] interfaces = realSubject.getClass().getInterfaces();
Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler);
proxySubect.doSomething("这是一个Dynamic AOP示例!!!");
}
}
```

#### 应用场景

动态代理模式在实际开发中有着广泛的应用,尤其是在框架和中间件中。例如,Spring AOP、DBCP连接池、AspectJ等都大量使用了动态代理技术。

总结来说,动态代理模式提供了一种灵活的方式来增强现有类的功能,而无需修改其源代码。这对于构建可扩展、可维护的系统具有重要意义。
推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • MQTT技术周报:硬件连接与协议解析
    本周开发笔记重点介绍了在新项目中使用MQTT协议进行硬件连接的技术细节,涵盖其特性、原理及实现步骤。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • 在使用 DataGridView 时,如果在当前单元格中输入内容但光标未移开,点击保存按钮后,输入的内容可能无法保存。只有当光标离开单元格后,才能成功保存数据。本文将探讨如何通过调用 DataGridView 的内置方法解决此问题。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
author-avatar
手机用户2502922607
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有