最近遇到一个需求,需要在某个位置,统一处理对象的一些属性值:
方案有两种:
这里有现成的hutool 方法,当然不用自己造轮子了,废话不多说,直接上代码:
这里有个类,我设置了id为12 ,我想将id属性值修改为2
public class MainTet {
public static void main(String[] args) {
Menu menu = new Menu();
menu.setMenuCode("12");
menu.setId(12);
Map<String, Object> overrideProps = new HashMap<>();
overrideProps.put("id", 2);
Menu menu1 = overrideField(menu,overrideProps);
System.out.println(JSONUtil.toJsonStr(menu1));
System.out.println(JSONUtil.toJsonStr(menu));
}
private static <T> T overrideField(T menu,Map<String, Object> overrideProps) {
Object object = BeanUtil.copyProperties(menu, menu.getClass());
for (Map.Entry<String, Object> entry : overrideProps.entrySet()) {
BeanUtil.setFieldValue(object, entry.getKey(), entry.getValue());
}
return (T) object;
}
}
可以看到,返回了新对象,然后值已经被修改,原值仍然是12;
这个就不一般了,它不是新建了对象,而是创建了一个代理类,类似于spring中的代理对象,然后它不修改之前对象的属性,而是增强
大致思路:
public class MainTet {
public static void main(String[] args) {
Menu menu = new Menu();
menu.setMenuCode("12");
menu.setId(12);
Map<String, Object> overrideProps = new HashMap<>();
overrideProps.put("id", 2);
Menu proxy = getProxy(menu,overrideProps);
System.out.println(proxy.getId());
}
private static <T> T getProxy(T menu, Map<String, Object> overrideProps) {
// 创建代理对象
ProxyFactory proxyFactory = new ProxyFactory(menu);
proxyFactory.setProxyTargetClass(Boolean.TRUE);
Map<String, Object> overrideMap = new HashMap<>();
// 设置代理对象的代理方法
// 例如 key为id 那么 overrideMap 中的key为getId 和 isid
overrideProps.forEach((k, v) -> {
String methodName = "get" + k.substring(0, 1).toUpperCase() + k.substring(1);
overrideMap.put(methodName, v);
methodName = "is" + k.substring(0, 1).toUpperCase() + k.substring(1);
overrideMap.put(methodName, v);
});
// 利用方法拦截器拦截调用方法,执行代理方法
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String methodName = invocation.getMethod().getName();
if (overrideMap.containsKey(methodName)) {
// 直接返回覆盖值,不执行原方法
return overrideMap.get(methodName);
}
// 执行原方法
return invocation.proceed();
}
});
return (T) proxyFactory.getProxy();
}
}
也被更为了2
因为,代理后,根本不会执行真正的getId 方法,而是在 MethodInterceptor的 invoke 中,根据判断,直接返回覆盖值
第二种方式比较高大上,相当于手动创建了代理对象,并修改了对象的原有属性和行为!