java动态代理实现aop的核心是proxy与invocationhandler,运行时为接口生成代理对象并织入横切逻辑;jdk代理仅支持接口,代理类需用cglib。

Java 类中使用动态代理实现 AOP 切面,核心是借助 java.lang.reflect.Proxy 和 InvocationHandler,在运行时为接口生成代理对象,拦截方法调用并织入横切逻辑(如日志、事务、权限校验等)。注意:JDK 动态代理仅支持对接口代理;若需代理具体类,得用 CGLIB(非 JDK 原生,需额外依赖)。
定义目标接口和实现类
动态代理基于接口,所以先要有接口:
public interface UserService {
String getName();
void save(String name);
}
再写一个实现类(不强制,但便于测试):
public class UserServiceImpl implements UserService {
@Override
public String getName() {
return "Alice";
}
@Override
public void save(String name) {
System.out.println("Saving: " + name);
}
}
编写 InvocationHandler 实现切面逻辑
这是真正的“切面”载体,所有代理方法调用都会进入 invoke 方法:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
public class LoggingInvocationHandler implements InvocationHandler {
private final Object target; // 被代理的真实对象
public LoggingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[Before] Calling: " + method.getName());
Object result = method.invoke(target, args); // 执行原方法
System.out.println("[After] Done: " + method.getName());
return result;
}
}
- 构造时传入真实对象(如
new UserServiceImpl()),保证可调用原逻辑 -
invoke中可做前置增强(Before)、后置增强(After)、异常增强(try-catch) - 返回值必须是
method.invoke(...)的结果,否则代理方法将无返回
创建代理对象并使用
用 Proxy.newProxyInstance 创建代理实例:
UserService userService = new UserServiceImpl();
InvocationHandler handler = new LoggingInvocationHandler(userService);
UserService proxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(), // 类加载器
userService.getClass().getInterfaces(), // 代理的接口数组
handler // 处理器
);
// 调用代理对象的方法,会触发 LoggingInvocationHandler.invoke()
System.out.println(proxy.getName()); // 输出 [Before]... [After]... 和 "Alice"
proxy.save("Bob"); // 同样被拦截
- 类加载器通常用目标对象的
getClass().getClassLoader() -
getInterfaces()确保代理实现相同接口,才能强转成功 - 代理对象不是
new出来的,不能直接new LoggingInvocationHandler(...)当业务对象用
进阶:模拟 Around 通知与注解驱动切面
想更贴近 Spring AOP 的 @Around 风格?可在 invoke 中封装执行过程:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("@Around before: " + method.getName());
try {
Object result = method.invoke(target, args);
System.out.println("@Around after returning: " + method.getName());
return result;
} catch (Exception e) {
System.out.println("@Around after throwing: " + e.getMessage());
throw e;
}
}
若希望按方法注解(如 @Loggable)决定是否增强,可在 invoke 中检查 method.isAnnotationPresent(Loggable.class),条件执行日志逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










