如何判断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
相关产品推荐
相关产品推荐

