1172 字
3 分钟
从回调与代理认识AOP

反射机制#

Reflect语言机制

在程序运行时期,能够通过一些手段,获取到类的信息(类名,方法,字段,构造器等),java动态代理底层就是靠的这个机制


回调方法#

Callback控制反转

方法内部执行步骤已经规定,缺省的逻辑 由 回调函数 根据实际需求补全

Java的回调函数三要素:

1.回调接口:声明要回调的方法 2.回调接口实现类:可用 匿名内部类(一个回调方法) 或者 用lambda表达式(多个回调方法)省略 3.回调触发者:传回调接口的实现类(谁会用到这段回调),方法内部规调用步骤

// 回调接口
public interface Callback {
void invoke1();
void invoke2();
}
// 回调接口实现
public class CallbackImpl implements Callback{
@Override
public void invoke1() {
System.out.println("待补全方法1");
}
@Override
public void invoke2() {
System.out.println("待补全方法2");
}
}
// 回调触发者
public class CallbackHandler {
//需要回调方法
public void invoke(Callback callback){
System.out.println("---------------------------");
System.out.println("额外逻辑1...");
callback.invoke1(); //回调方法
System.out.println("额外逻辑2...");
System.out.println("额外逻辑3...");
callback.invoke2(); //回调方法
System.out.println("---------------------------");
}
}
// 测试
public class Test {
public static void main(String[] args) {
// 调用函数
CallbackHandler callbackHandler = new CallbackHandler();
// 传入接口的实现类
callbackHandler.invoke(new CallbackImpl());
}
}

结果

------------------------------
业务逻辑1...
待补全方法1
业务逻辑2...
业务逻辑3...
待补全方法2
------------------------------

代理模式#

Proxy Pattern设计模式

代理对象 替代 真实对象 处理请求 ,把“非核心逻辑”从真实对象中剥离出来,由代理统一处理

a951fc02-ffa4-4053-be5d-38ca01e6b329

例如

客户(发出请求) → 找房中介(代理) → 房东(真实对象)

  1. 房东提供房子
  2. 房东让中介处理其他操作、服务(带人看房,拟定合同),增强服务体验
  3. 客户执行操作找中介就行

功能

控制访问:不让用户直接接触核心业务,保护安全

功能增强:你想给现有功能“加料”但不改原有代码

简化业务:真实对象只关注核心业务,可能会和其他对象类似的功能,统一提取出来交给代理去做

静态代理#

编译前写死的代码(硬编码)

动态代理#

运行时生成、基于反射实现、

Java Proxy#

Java代理:接口实现

image-20260129232455651

手动静态代理#

只能代理一个接口的多个实现类,接口只规定核心业务方法。 实现类、静态代理类 继承 同一个接口 ​代理类重写方法 调用 实现类重写方法 并附加其他功能

[!tip] 思考 如果把target类型设计为最顶层接口,通过把多个接口重新组合为一个接口,则不符合规范,其余实现类必须实现与自己无关的抽象方法。并且上层是调用不了下层的特有方法,用强转会写的太死,脱离了代理思想。

// 接口
public interface UserService {
void addUser(String name);
}
// 实现类
public class UserServiceImpl implements UserService{
@Override
public void addUser(String name) {
System.out.println("添加用户 " + name + " 成功");
}
}
// 实现类代理
public class UserServiceProxy implements UserService{
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void addUser(String name) {
System.out.println("代理:[权限检查]");// 前置额外逻辑
target.addUser(name); //UserService真实对象的核心业务逻辑
System.out.println("代理:[日志上传]");// 后置额外逻辑
}
}
// 调用
public class ProxyTest {
public static void main(String[] args) {
UserService proxy = new UserServiceProxy(new UserServiceImpl());
proxy.addUser("张三");
}
}
/* 结果
代理:[权限检查]
添加用户 张三 成功
代理:[日志上传]
*/

JDK动态代理#

反射回调方法

coder手动创建的静态代理(麻烦) -> JVM用反射动态生成的静态代理(方便) 因为静态代理要获取实现类接口,所以JVM要知道你用的什么接口; 因为是动态生成的,所以里面的步骤控制权要转让给编写代码的人,就要用回调方法(invoke())。 以上是我对动态代理的核心理解,其本质就是由jvm创造的静态代理

实现流程图image-20260127201103034

Proxy 动态代理类

// Proxy
public static Object newProxyInstance(
ClassLoader loader, // 用target类加载器
Class<?>[] interfaces, // 用target的接口:硬性规定只能代理接口
InvocationHandler h // 传入回调实现类: 要求重写回调方法,用于承载“方法调用时的统一处理逻辑”。
)

InvotationHandler 动态代理的回调接口

Interface InvotationHandler{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

自定义的工具类 ProxyUtil 封装写好的回调方法invoke

public class ProxyUtil {
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
// InvokeHandler接口定义的回调方法,控制权在程序员手里
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[权限检测]");// 前置 额外逻辑
Object o = method.invoke(target, args);// 反射包下invoke 调用真实对象方法
System.out.println("[日志记录]");// 后置 额外逻辑
return o;
}
}
);
}
}

JDK动态生成的代理类(大致长这样)

// 发现没有,和静态代理一样的,区别只有不是写死的,JDK动态生成的
// 即是代理,也是CallbackInvoker类
public final class $Proxy0 extends Proxy implements UserService {
private static Method m_addUser;
static {
try {
m_addUser = UserService.class
.getMethod("addUser", String.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
// 父类 Proxy 已经持有 InvocationHandler h
public $Proxy0(InvocationHandler h) {
super(h);
}
@Override
public void addUser(String name) {
try {
// invoactionHandler.invoke(), 所有接口方法 → 回调调用者
h.invoke(this, m_addUser, new Object[]{name});
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
}

AOP#

Aspect-Oriented Programming面向切面编程编程范式

​ 将一些对象需要的类似功能提取出来组织,通过动态代理实现,和代理模式概念一致。区别在于将通用增强逻辑以声明式方式集中管理,实现对业务代码的非侵入式横切增强。故是代理模式的上层


总结#

回调 (IOC基本方法) 补齐 外部规定模板方法的 缺失逻辑/行为

静态代理 (复用性 ↑) 手写的代理类和实现类继承同一组接口,在代理类同名方法 调用 实现类同名方法 + 通用增强逻辑

动态代理 (复用性 ↑) 运行时生成代理类,代理类同名方法由回调反射实现(自己写)

AOP (扩展性 ↑) 动态代理 + 以声明式方式将通用增强逻辑集中管理,实现对业务代码的非侵入式横切增强 (有些实现类用增强逻辑A,有些用增强逻辑B,程序员进行调配、选择、简化开发)


面向接口 有了更深理解,重要程度不亚于C指针; 剖析时 加强了对匿名内部类、lambda进一步理解(语法糖); 引出 编程范式、设计思想、接口的default方法、钩子和回调区别、还需继续学习


分享

如果这篇文章对你有帮助,欢迎分享给更多人!

从回调与代理认识AOP
https://mizuki.mysqil.com/posts/aop思想/
作者
Oddpalmer
发布于
2026-01-29
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时