You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断Session中House对象的streetAddress字段是否被访问过?

解决方案

要跟踪Session中House对象的streetAddress字段对应的getter/setter是否被调用过,直接用反射确实没法实现(反射只能获取方法定义,无法跟踪运行时调用状态),下面是几个可行的落地方案:

方案1:直接修改House类(最简单,若允许修改源码)

在House类中添加两个布尔标记,分别记录getter和setter的调用状态,在对应方法中更新标记,再提供获取标记的方法:

public class House {
    private String streetAddress;
    // 记录调用状态的标记
    private boolean isStreetAddressGetterCalled = false;
    private boolean isStreetAddressSetterCalled = false;

    public String getStreetAddress() {
        // 调用getter时标记为true
        isStreetAddressGetterCalled = true;
        return streetAddress;
    }

    public void setStreetAddress(String streetAddress) {
        // 调用setter时标记为true
        isStreetAddressSetterCalled = true;
        this.streetAddress = streetAddress;
    }

    // 获取调用状态的方法
    public boolean isStreetAddressGetterCalled() {
        return isStreetAddressGetterCalled;
    }

    public boolean isStreetAddressSetterCalled() {
        return isStreetAddressSetterCalled;
    }

    // 可选:如果需要重置会话中的状态,可以添加重置方法
    public void resetAddressCallFlags() {
        isStreetAddressGetterCalled = false;
        isStreetAddressSetterCalled = false;
    }
}

在method2中直接调用这两个状态方法判断:

// 从Session取出House对象
House house = (House) session.getAttribute("house");
if (house.isStreetAddressGetterCalled()) {
    // getter被调用过
}
if (house.isStreetAddressSetterCalled()) {
    // setter被调用过
}

方案2:用装饰器模式包装House(不修改原类)

如果不能修改House的源码,可通过装饰器包装House实例,将包装后的对象存入Session,所有对House的操作都会经过装饰器,从而记录调用状态:

情况A:House实现了接口

假设House实现了IHouse接口:

// 原House的接口
public interface IHouse {
    String getStreetAddress();
    void setStreetAddress(String streetAddress);
    // 其他方法...
}

public class House implements IHouse {
    // 原有的代码逻辑
}

// 装饰器类
public class TrackedHouse implements IHouse {
    private final IHouse target;
    private boolean getterCalled = false;
    private boolean setterCalled = false;

    public TrackedHouse(IHouse target) {
        this.target = target;
    }

    @Override
    public String getStreetAddress() {
        getterCalled = true;
        return target.getStreetAddress();
    }

    @Override
    public void setStreetAddress(String streetAddress) {
        setterCalled = true;
        target.setStreetAddress(streetAddress);
    }

    // 其他方法直接转发给target...

    // 获取调用状态
    public boolean isGetterCalled() {
        return getterCalled;
    }

    public boolean isSetterCalled() {
        return setterCalled;
    }
}

存入Session时替换为装饰器实例:

IHouse originalHouse = new House();
IHouse trackedHouse = new TrackedHouse(originalHouse);
session.setAttribute("house", trackedHouse);

method2中取出并判断:

TrackedHouse trackedHouse = (TrackedHouse) session.getAttribute("house");
if (trackedHouse.isGetterCalled()) {
    // getter被调用过
}

情况B:House无接口(用继承实现装饰)

如果House没有实现接口,可通过继承House来实现跟踪:

public class TrackedHouse extends House {
    private boolean getterCalled = false;
    private boolean setterCalled = false;

    @Override
    public String getStreetAddress() {
        getterCalled = true;
        return super.getStreetAddress();
    }

    @Override
    public void setStreetAddress(String streetAddress) {
        setterCalled = true;
        super.setStreetAddress(streetAddress);
    }

    public boolean isGetterCalled() {
        return getterCalled;
    }

    public boolean isSetterCalled() {
        return setterCalled;
    }
}

使用方式和接口版本一致,存入Session时存TrackedHouse实例即可。

方案3:动态代理(适合不想写装饰类的场景)

如果不想手动编写装饰类,可以用动态代理(JDK动态代理或CGLIB)在运行时生成代理对象,拦截方法调用并记录状态:

以下是CGLIB代理的示例(需引入CGLIB依赖):

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;

public class HouseProxyCreator {
    // 生成带调用跟踪的House代理对象
    public static House createTrackedHouse(House original, AtomicBoolean getterFlag, AtomicBoolean setterFlag) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(House.class);
        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
            // 拦截getter和setter方法
            if ("getStreetAddress".equals(method.getName())) {
                getterFlag.set(true);
            } else if ("setStreetAddress".equals(method.getName())) {
                setterFlag.set(true);
            }
            // 执行原方法逻辑
            return proxy.invokeSuper(obj, args);
        });
        // 根据原House的构造方法参数调整这里的参数,示例假设House有String类型的构造参数
        return (House) enhancer.create(new Class[]{String.class}, new Object[]{original.getStreetAddress()});
    }
}

使用时,将标记对象和代理对象一起存入Session:

AtomicBoolean getterCalled = new AtomicBoolean(false);
AtomicBoolean setterCalled = new AtomicBoolean(false);
House originalHouse = new House();
House trackedHouse = HouseProxyCreator.createTrackedHouse(originalHouse, getterCalled, setterCalled);
session.setAttribute("house", trackedHouse);
session.setAttribute("getterFlag", getterCalled);
session.setAttribute("setterFlag", setterCalled);

method2中取出标记判断:

AtomicBoolean getterCalled = (AtomicBoolean) session.getAttribute("getterFlag");
if (getterCalled.get()) {
    // getter被调用过
}

内容的提问来源于stack exchange,提问作者Archibald

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 06:55:12