文章目录
- 前言
- 一、复制一个对象
- 二、代理对象
- 重点来了
- 总结
前言
最近遇到一个需求,需要在某个位置,统一处理对象的一些属性值:
方案有两种:
- 直接复制一份,将属性覆盖后,返回一个新对象
- 搞一个代理类,代理这个对象,修改对象的原有行为和值,从而达到修改属性值的目的
一、复制一个对象
这里有现成的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 和 isidoverrideProps.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() {@Overridepublic 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 中,根据判断,直接返回覆盖值
总结
第二种方式比较高大上,相当于手动创建了代理对象,并修改了对象的原有属性和行为!