Java 使用动态代理和反射实现字段变更跟踪

下面我将展示如何使用Java动态代理和反射技术来跟踪记录对象字段的变更前和变更后的数据。

实现方案

我们将创建一个FieldChangeTracker代理,它能够:

  1. 在字段被修改前记录原始值

  2. 在字段被修改后记录新值

  3. 将所有变更记录保存在日志中

1. 创建变更记录数据结构

import java.util.Date;

public class FieldChangeRecord {
    private String fieldName;
    private Object oldValue;
    private Object newValue;
    private Date changeTime;
    private String methodName;

    public FieldChangeRecord(String fieldName, Object oldValue, Object newValue, String methodName) {
        this.fieldName = fieldName;
        this.oldValue = oldValue;
        this.newValue = newValue;
        this.changeTime = new Date();
        this.methodName = methodName;
    }

    @Override
    public String toString() {
        return "FieldChangeRecord{" +
                "fieldName='" + fieldName + '\'' +
                ", oldValue=" + oldValue +
                ", newValue=" + newValue +
                ", changeTime=" + changeTime +
                ", methodName='" + methodName + '\'' +
                '}';
    }
}

2. 创建变更跟踪处理器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class FieldChangeTracker implements InvocationHandler {
    private final Object target;
    private final List<FieldChangeRecord> changeHistory = new ArrayList<>();

    public FieldChangeTracker(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 只拦截setter方法
        if (method.getName().startsWith("set") && args != null && args.length == 1) {
            // 获取字段名(从setXxx转换为xxx)
            String fieldName = method.getName().substring(3);
            fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1);

            try {
                // 获取字段当前值(变更前)
                Field field = target.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Object oldValue = field.get(target);
                
                // 调用原始方法修改值
                Object result = method.invoke(target, args);
                
                // 获取字段新值(变更后)
                Object newValue = field.get(target);
                
                // 记录变更
                changeHistory.add(new FieldChangeRecord(
                    fieldName, oldValue, newValue, method.getName()));
                
                return result;
            } catch (NoSuchFieldException e) {
                // 如果没有对应字段,直接调用方法
                return method.invoke(target, args);
            }
        } else {
            // 非setter方法直接调用
            return method.invoke(target, args);
        }
    }

    public List<FieldChangeRecord> getChangeHistory() {
        return new ArrayList<>(changeHistory);
    }

    public void printChangeHistory() {
        System.out.println("=== Field Change History ===");
        for (FieldChangeRecord record : changeHistory) {
            System.out.println(record);
        }
        System.out.println("===========================");
    }
}

3. 创建代理工厂

import java.lang.reflect.Proxy;

public class TrackingProxyFactory {
    @SuppressWarnings("unchecked")
    public static <T> T createTrackingProxy(T target, Class<T> interfaceType) {
        return (T) Proxy.newProxyInstance(
                interfaceType.getClassLoader(),
                new Class<?>[]{interfaceType},
                new FieldChangeTracker(target));
    }
}

4. 示例使用

public interface User {
    String getName();
    void setName(String name);
    int getAge();
    void setAge(int age);
}

public class UserImpl implements User {
    private String name;
    private int age;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int getAge() {
        return age;
    }

    @Override
    public void setAge(int age) {
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        User realUser = new UserImpl();
        User userProxy = TrackingProxyFactory.createTrackingProxy(realUser, User.class);
        
        userProxy.setName("Alice");
        userProxy.setAge(25);
        userProxy.setName("Bob");
        userProxy.setAge(30);
        
        // 获取变更历史
        FieldChangeTracker tracker = (FieldChangeTracker) Proxy.getInvocationHandler(userProxy);
        tracker.printChangeHistory();
    }
}

5. 示例输出

运行上面的Main类后,输出可能如下:

=== Field Change History ===
FieldChangeRecord{fieldName='name', oldValue=null, newValue=Alice, changeTime=..., methodName='setName'}
FieldChangeRecord{fieldName='age', oldValue=0, newValue=25, changeTime=..., methodName='setAge'}
FieldChangeRecord{fieldName='name', oldValue=Alice, newValue=Bob, changeTime=..., methodName='setName'}
FieldChangeRecord{fieldName='age', oldValue=25, newValue=30, changeTime=..., methodName='setAge'}
===========================

高级改进

  1. 支持非接口类:可以使用CGLIB库来代理没有接口的类

  2. 线程安全:为changeHistory添加同步控制

  3. 过滤敏感字段:添加注解标记不需要跟踪的字段

  4. 持久化存储:将变更记录保存到数据库或文件

  5. 性能优化:缓存反射获取的Field对象

CGLIB版本实现

如果需要代理没有实现接口的类,可以使用CGLIB:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibTrackingProxyFactory {
    @SuppressWarnings("unchecked")
    public static <T> T createTrackingProxy(T target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new CglibFieldChangeTracker(target));
        return (T) enhancer.create();
    }
}

class CglibFieldChangeTracker implements MethodInterceptor {
    private final Object target;
    private final List<FieldChangeRecord> changeHistory = new ArrayList<>();

    public CglibFieldChangeTracker(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 实现逻辑与FieldChangeTracker类似
        // ...
    }
    
    // 其他方法与FieldChangeTracker相同
}

这种实现方式可以跟踪任何类的字段变更,而不仅限于实现了接口的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值