文章目录
- 前言
- 一、复制一个对象
- 二、代理对象
- 重点来了
- 总结
前言
最近遇到一个需求,需要在某个位置,统一处理对象的一些属性值:
方案有两种:
- 直接复制一份,将属性覆盖后,返回一个新对象
- 搞一个代理类,代理这个对象,修改对象的原有行为和值,从而达到修改属性值的目的
一、复制一个对象
这里有现成的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
重点来了
- 我在Menu对的getId() 方法中打了断点,但是debug运行过程中,并不会到此处断点
因为,代理后,根本不会执行真正的getId 方法,而是在 MethodInterceptor的 invoke 中,根据判断,直接返回覆盖值
总结
第二种方式比较高大上,相当于手动创建了代理对象,并修改了对象的原有属性和行为!