直接用内部类实现动态代理添加事务切面是脱离spring的轻量方案:通过私有静态内部类实现invocationhandler,在invoke中识别增删改方法并统一管理连接、开启/提交/回滚事务,业务类须实现接口,使用proxy.newproxyinstance生成代理实例。

直接用内部类实现动态代理来添加事务切面,是脱离 Spring 框架时一种轻量、可控的落地方式。核心思路是:把事务控制逻辑封装在 内部的 InvocationHandler 实现类 中,再通过 Proxy.newProxyInstance 为目标业务对象(必须实现接口)生成代理实例。整个过程不依赖外部框架,逻辑清晰、便于调试。
前提:业务对象必须基于接口
JDK 动态代理只支持对接口代理,因此你的业务类得先定义接口并实现它。例如:
-
接口:
UserService(含addUser()、deleteUser()等方法) -
实现类:
UserServiceImpl,专注写纯业务逻辑,不碰事务 - 不能对
UserServiceImpl这个类本身代理,只能代理它所实现的UserService接口
内部类封装事务处理器
在调用方类(比如工具类或配置类)中,定义一个私有静态内部类,实现 InvocationHandler。它持有原始业务对象,并在 invoke() 中统一管理事务:
- 识别增删改方法(如方法名以
"add"、"update"、"delete"开头) - 从连接池或 ThreadLocal 获取数据库连接
- 开启事务 → 执行原方法 → 成功则提交,异常则回滚
- 查询类方法(如
getUser())默认不开启事务(可配)
示例片段:
public class TransactionProxyFactory {
public static UserService createTransactionalUserService(UserService target) {
return (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new TransactionHandler(target) // 内部类实例
);
}
private static class TransactionHandler implements InvocationHandler {
private final UserService target;
TransactionHandler(UserService target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Connection conn = ConnectionManager.get();
boolean needTx = method.getName().startsWith("add")
|| method.getName().startsWith("update")
|| method.getName().startsWith("delete");
if (needTx) {
conn.setAutoCommit(false);
}
try {
Object result = method.invoke(target, args);
if (needTx) conn.commit();
return result;
} catch (Exception e) {
if (needTx) conn.rollback();
throw e;
}
}
}
}
使用方式简洁明确
业务代码无需改动,只需替换对象创建方式:
- 原来:
UserService service = new UserServiceImpl(); - 现在:
UserService service = TransactionProxyFactory.createTransactionalUserService(new UserServiceImpl()); - 后续所有对
service的调用,都自动经过事务拦截
注意事项与边界处理
这种内部类方式虽简单,但要注意几个实际细节:
-
Connection 管理必须线程安全:推荐用
ThreadLocal<connection></connection>避免多线程串连 -
异常类型要覆盖全:除了
SQLException,还要捕获RuntimeException触发回滚 -
不要代理 equals/hashCode/toString:这些方法若被代理可能破坏对象行为,可在
invoke中跳过 - 事务传播暂不支持:这是简易版,嵌套调用需额外设计(如检查当前已有事务)











