一、故事解说:孙悟空的毫毛如何帮他打怪
假设孙悟空遇到妖怪:
-
本体专注战斗:孙悟空负责挥金箍棒打怪,不关心其他杂事;
-
毫毛分身当代理:
- 变个分身去引开妖怪注意力(预处理);
- 本体打完怪后,分身清理战场(后处理);
-
动态变化:遇到不同妖怪,毫毛可以动态变化(如变成牛魔王、土地公)。
动态代理核心:在运行时动态创建代理对象,代理对象的方法调用会被拦截,可添加预处理 / 后处理逻辑,无需像静态代理那样提前写好代理类。
二、动态代理核心结构(Java 反射实现)
java
// 1. 共同接口:妖怪(被代理的接口)
interface Monster {
void attack(); // 攻击方法
String getName(); // 获取名字
}
// 2. 真实对象:具体妖怪
class Skeleton implements Monster {
@Override
public void attack() {
System.out.println("骷髅怪用骨头攻击");
}
@Override
public String getName() {
return "骷髅怪";
}
}
// 3. 调用处理器:拦截方法调用,添加额外逻辑
class MonsterInvocationHandler implements InvocationHandler {
private final Object target; // 真实对象
public MonsterInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 预处理:引开注意力
System.out.println("孙悟空分身引开" + ((Monster) target).getName() + "的注意力");
// 调用真实方法
Object result = method.invoke(target, args);
// 后处理:清理战场
System.out.println("孙悟空分身清理" + ((Monster) target).getName() + "的残骸");
return result;
}
}
// 4. 客户端:动态创建代理并调用方法
public class Client {
public static void main(String[] args) {
// 创建真实对象
Monster realMonster = new Skeleton();
// 创建InvocationHandler
InvocationHandler handler = new MonsterInvocationHandler(realMonster);
// 动态创建代理对象
Monster proxyMonster = (Monster) Proxy.newProxyInstance(
Monster.class.getClassLoader(),
new Class<?>[]{Monster.class},
handler
);
// 调用代理对象的方法
proxyMonster.attack();
// 输出:
// 孙悟空分身引开骷髅怪的注意力
// 骷髅怪用骨头攻击
// 孙悟空分身清理骷髅怪的残骸
}
}
三、Android 常用动态代理案例与实现
案例 1:View 点击事件的动态代理(替代静态代理)
java
// 1. 共同接口:点击事件
interface OnClickListener {
void onClick(View v);
}
// 2. 真实点击逻辑:Activity中的点击处理
class RealOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
System.out.println("真实逻辑:跳转到详情页");
}
}
// 3. 调用处理器:添加权限检查
class PermissionInvocationHandler implements InvocationHandler {
private final Object target;
private final Context context;
public PermissionInvocationHandler(Context context, Object target) {
this.context = context;
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 预处理:检查权限
if (method.getName().equals("onClick") && !checkPermission(context)) {
System.out.println("代理:权限不足,提示用户授权");
return null;
}
// 调用真实方法
return method.invoke(target, args);
}
private boolean checkPermission(Context context) {
// 实际中检查权限
return true;
}
}
// 4. 在Activity中使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View button = findViewById(R.id.button);
// 创建真实点击监听器
OnClickListener realListener = v -> {
System.out.println("跳转到详情页");
};
// 创建动态代理
OnClickListener proxyListener = (OnClickListener) Proxy.newProxyInstance(
OnClickListener.class.getClassLoader(),
new Class<?>[]{OnClickListener.class},
new PermissionInvocationHandler(this, realListener)
);
// 设置代理监听器
button.setOnClickListener(proxyListener);
}
}
优点:
-
零代码侵入:无需创建具体代理类,直接在运行时生成代理;
-
灵活扩展:可在运行时动态添加 / 修改代理逻辑(如不同按钮添加不同权限检查);
-
减少类数量:相比静态代理,无需为每个功能创建代理类。
缺点:
- 只能代理接口:Java 动态代理只能代理实现了接口的类,无法代理普通类;
- 调试困难:代理逻辑分散在 InvocationHandler 中,出错时难以定位;
- 性能开销:反射调用方法比直接调用慢,频繁调用可能影响性能。
案例 2:Retrofit 的动态代理(网络请求接口代理)
java
// 1. 网络请求接口(定义API)
public interface ApiService {
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
}
// 2. 调用处理器:处理网络请求
class RetrofitInvocationHandler implements InvocationHandler {
private final String baseUrl;
public RetrofitInvocationHandler(String baseUrl) {
this.baseUrl = baseUrl;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 解析方法上的注解(如@GET、@Path)
String path = parsePathFromAnnotations(method);
String httpMethod = parseHttpMethodFromAnnotations(method);
// 2. 解析参数(如@Path、@Query)
Map<String, String> params = parseParamsFromArgs(method, args);
// 3. 构建完整URL
String url = baseUrl + path + buildQueryString(params);
// 4. 执行网络请求(简化示例)
System.out.println("发送" + httpMethod + "请求到:" + url);
return new MockCall<>(); // 实际中返回OkHttp的Call对象
}
// 解析注解和参数的方法(实际Retrofit实现更复杂)
private String parsePathFromAnnotations(Method method) { /* ... */ }
private String parseHttpMethodFromAnnotations(Method method) { /* ... */ }
private Map<String, String> parseParamsFromArgs(Method method, Object[] args) { /* ... */ }
private String buildQueryString(Map<String, String> params) { /* ... */ }
}
// 3. 模拟Call对象(实际Retrofit使用OkHttp的Call)
class MockCall<T> implements Call<T> {
@Override
public Response<T> execute() throws IOException { /* ... */ }
@Override
public void enqueue(Callback<T> callback) { /* ... */ }
// 省略其他方法
}
// 4. 创建代理实例(类似Retrofit.create())
public class Retrofit {
private final String baseUrl;
public Retrofit(String baseUrl) {
this.baseUrl = baseUrl;
}
@SuppressWarnings("unchecked")
public <T> T create(Class<T> service) {
return (T) Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[]{service},
new RetrofitInvocationHandler(baseUrl)
);
}
}
// 5. 使用方式
public class Main {
public static void main(String[] args) {
Retrofit retrofit = new Retrofit("https://api.github.com/");
ApiService api = retrofit.create(ApiService.class);
// 调用接口方法(实际会触发InvocationHandler的invoke)
Call<User> call = api.getUser("octocat");
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
System.out.println("获取用户成功");
}
@Override
public void onFailure(Call<User> call, Throwable t) {
System.out.println("获取用户失败");
}
});
}
}
优点:
-
零实现类:无需编写接口的实现类,直接通过代理动态生成;
-
注解驱动:通过注解(如 @GET、@Path)定义请求参数,代码简洁;
-
扩展性强:可在 InvocationHandler 中添加统一拦截逻辑(如添加 token、日志记录)。
缺点:
- 学习成本高:需要理解注解解析、反射调用等复杂机制;
- 调试困难:接口方法调用被转发到 InvocationHandler,堆栈信息不直观;
- 只能代理接口:无法代理普通类,限制了使用场景。
案例 3:权限检查的动态代理(替代 AOP)
java
// 1. 权限注解:标记需要权限的方法
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiresPermission {
String value(); // 权限名称
}
// 2. 业务接口:定义需要权限的方法
public interface UserService {
@RequiresPermission("read_user")
User getUserById(String userId);
@RequiresPermission("delete_user")
void deleteUser(String userId);
}
// 3. 真实实现类
public class UserServiceImpl implements UserService {
@Override
public User getUserById(String userId) {
System.out.println("获取用户:" + userId);
return new User(userId, "张三");
}
@Override
public void deleteUser(String userId) {
System.out.println("删除用户:" + userId);
}
}
// 4. 权限检查调用处理器
public class PermissionInvocationHandler implements InvocationHandler {
private final Object target;
private final Context context;
public PermissionInvocationHandler(Context context, Object target) {
this.context = context;
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 检查方法是否有@RequiresPermission注解
RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);
if (annotation != null) {
String permission = annotation.value();
// 2. 检查权限
if (!checkPermission(context, permission)) {
throw new SecurityException("权限不足:" + permission);
}
}
// 3. 调用真实方法
return method.invoke(target, args);
}
private boolean checkPermission(Context context, String permission) {
// 实际中检查权限
return true;
}
}
// 5. 创建代理工厂
public class ProxyFactory {
public static <T> T createProxy(Context context, T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new PermissionInvocationHandler(context, target)
);
}
}
// 6. 使用方式
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 创建真实对象
UserService realService = new UserServiceImpl();
// 创建代理对象
UserService proxyService = ProxyFactory.createProxy(this, realService);
// 调用方法(自动触发权限检查)
try {
proxyService.getUserById("123");
} catch (SecurityException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
优点:
-
非侵入式权限控制:无需在每个方法中手动添加权限检查代码;
-
集中管理权限:所有权限检查逻辑集中在 InvocationHandler 中;
-
灵活配置:通过注解(@RequiresPermission)标记需要权限的方法,无需修改原有代码。
缺点:
- 只能代理接口:如果 UserService 不是接口而是普通类,无法使用 Java 动态代理;
- 性能开销:反射调用比直接调用慢,频繁调用可能影响性能;
- 注解处理复杂:需要理解 Method.getAnnotation () 等反射 API。
四、动态代理的适用场景与总结
适用场景:
- 横切关注点:如权限检查、日志记录、事务管理(类似 AOP);
- 接口实现类缺失:如 Retrofit 需要动态实现 API 接口;
- 运行时动态增强:需要在运行时动态添加功能(如添加网络请求拦截器);
- 框架开发:如 Spring AOP、Retrofit、Mockito 等框架大量使用动态代理。
核心优点:
- 零代码侵入:无需修改原有代码,通过代理动态添加功能;
- 灵活扩展:可在运行时动态调整代理逻辑,无需重新编译;
- 减少类数量:相比静态代理,无需为每个功能创建独立代理类;
- 接口解耦:客户端只依赖接口,不依赖具体实现。
核心缺点:
- 只能代理接口:Java 动态代理要求目标类必须实现接口,限制了使用范围;
- 性能开销:反射调用比直接调用慢,对性能敏感的场景需谨慎使用;
- 调试困难:代理逻辑分散在 InvocationHandler 中,堆栈信息不直观;
- 学习成本高:需要理解反射、Method、InvocationHandler 等复杂概念。
Android 中的最佳实践:
-
优先使用系统动态代理:如 Retrofit、OkHttp 等框架已封装好动态代理,避免重复造轮子;
-
小型功能增强:用于简单的功能扩展(如点击事件添加权限检查),复杂场景改用字节码插桩(如 AspectJ);
-
结合 CGLIB:对于没有实现接口的类,可使用 CGLIB(需添加依赖)实现动态代理;
-
性能优化:在性能敏感场景(如循环中频繁调用),避免使用动态代理。
动态代理是 Java 和 Android 框架的核心技术之一,理解它有助于深入掌握 Retrofit、OkHttp、EventBus 等开源框架的工作原理。