java动态代理实现日志记录的核心是proxy与invocationhandler,通过接口代理在不修改源码前提下自动添加前置、后置及异常日志;需定义接口与实现类,编写含日志逻辑的invocationhandler,并用proxy.newproxyinstance创建代理对象。

Java 中用动态代理实现日志记录,核心是借助 java.lang.reflect.Proxy 和 InvocationHandler,在不修改目标类源码的前提下,自动为方法调用添加前置(如开始日志)、后置(如结束或返回日志)、异常日志等逻辑。
1. 定义被代理的接口和实现类
动态代理要求目标对象必须实现接口(JDK 代理限制),所以先定义一个业务接口:
public interface UserService {
String getName(int id);
void updateUser(String name, int age);
}
再提供一个简单实现:
public class UserServiceImpl implements UserService {
@Override
public String getName(int id) {
return "Alice";
}
@Override
public void updateUser(String name, int age) {
System.out.println("Updating user: " + name + ", age: " + age);
}
}
2. 编写日志增强的 InvocationHandler
这是关键组件,所有代理逻辑(包括日志)都写在这里:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
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 {
String methodName = method.getName();
Class>[] paramTypes = method.getParameterTypes();
// 前置日志:方法名 + 参数
System.out.println("[LOG] Entering " + methodName + "(" +
java.util.Arrays.toString(args) + ")");
Object result = null;
try {
// 执行原方法
result = method.invoke(target, args);
// 返回日志
System.out.println("[LOG] Exiting " + methodName + " → " + result);
return result;
} catch (Exception e) {
// 异常日志
System.out.println("[LOG] Exception in " + methodName + ": " + e.getMessage());
throw e;
}
}
}
3. 创建代理对象并使用
在测试或业务代码中,用 Proxy.newProxyInstance 创建代理实例:
public class Main {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
// 创建代理:ClassLoader、接口数组、处理器
UserService proxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new LoggingInvocationHandler(userService)
);
// 调用方法 —— 日志会自动打印
String name = proxy.getName(1001); // 输出进入/退出日志
proxy.updateUser("Bob", 28); // 同样触发日志
}
}
4. 可选优化点
-
按方法名或注解控制日志开关:在
invoke中检查method.isAnnotationPresent(Logging.class),只对加了注解的方法记录 -
记录执行耗时:在
invoke开头记System.nanoTime(),结尾计算差值并打印 -
替换为 SLF4J 或 Logback:把
System.out.println换成logger.info(),更符合生产规范 - 支持私有方法或非接口类:需改用 CGLIB(如 Spring AOP 默认方式),但 JDK 动态代理无需额外依赖
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











