Apache Commons Beanutils对象属性批量复制(pseudo-singleton)
Apache Commons Beanutils为开源软件,可在Apache官网http://commons.apache.org/proper/commons-beanutils/download_beanutils.cgi下载,使用它还需另一个Apache开源软件Apache Commons Logging,可在Apache官网http://commons.apache.org/proper/commons-logging/download_logging.cgi下载,我使用的是commons-beanutils-1.9.1-bin.zip和commons-logging-1.1.3-bin.zip
public class User { private String name; private Integer age; private boolean single; private Map<Integer,Integer> map; public User(){} public User(String name,Integer age,boolean single, Map<Integer,Integer> map){ this.name = name; this.age = age; this.single = single; this.map = map; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSingle() { return single; } public void setSingle(boolean single) { this.single = single; } public Map<Integer, Integer> getMap() { return map; } public void setMap(Map<Integer, Integer> map) { this.map = map; } public String toString(){ String str = "name:"+name+" age:"+age+" single:"+single+" "; if(null != map && map.size() > 0){ str += "map["; Iterator<Integer> it = map.keySet().iterator(); while(it.hasNext()){ Integer key = it.next(); Integer value = map.get(key); str += key+":"+value+" "; } str += "]"; } return str; } }
package com.sean; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; public class Test { public static void main(String[] args) throws Exception { Map<Integer,Integer> map = new HashMap<Integer,Integer>(); map.put(1, 1); User u1 = new User("tom",123,true,map); User u2 = new User(); BeanUtils.copyProperties(u2, u1); System.out.println(u1.toString()); System.out.println(u2.toString()); } }
运行结果为(比较复杂的属性也可以被复制并且只有拥有get/set方法的属性才可以被复制):
name:tom age:123 single:true map[1:1 ] name:tom age:null single:true map[1:1 ]
更详细的使用说明就不介绍了,接下来看看BeanUtils是如何实现的,好戏刚刚开始
BeanUtils:
....... public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException { BeanUtilsBean.getInstance().copyProperties(dest, orig); } ...... /** * Gets the instance which provides the functionality for {@link BeanUtils}. * This is a pseudo-singleton - an single instance is provided per (thread) context classloader. * This mechanism provides isolation for web apps deployed in the same container. * * @return The (pseudo-singleton) BeanUtils bean instance */ public static BeanUtilsBean getInstance() { return BEANS_BY_CLASSLOADER.get(); } ......
这里特意带上了方法说明,getInstance()方法并不是一个简单的单例模式,而是一个“伪单例”模式
ContextClassLoaderLocal<T>:
...... private static final ContextClassLoaderLocal<BeanUtilsBean> BEANS_BY_CLASSLOADER = new ContextClassLoaderLocal<BeanUtilsBean>() { // Creates the default instance used when the context classloader is unavailable @Override protected BeanUtilsBean initialValue() { return new BeanUtilsBean(); } }; ...... /** * Gets the instance which provides the functionality for {@link BeanUtils}. * This is a pseudo-singleton - an single instance is provided per (thread) context classloader. * This mechanism provides isolation for web apps deployed in the same container. * @return the object currently associated with the context-classloader of the current thread. */ public synchronized T get() { // synchronizing the whole method is a bit slower // but guarantees no subtle threading problems, and there's no // need to synchronize valueByClassLoader // make sure that the map is given a change to purge itself valueByClassLoader.isEmpty(); try { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null) { T value = valueByClassLoader.get(contextClassLoader); if ((value == null) && !valueByClassLoader.containsKey(contextClassLoader)) { value = initialValue(); valueByClassLoader.put(contextClassLoader, value); } return value; } } catch (SecurityException e) { /* SWALLOW - should we log this? */ } // if none or exception, return the globalValue if (!globalValueInitialized) { globalValue = initialValue(); globalValueInitialized = true; }//else already set return globalValue; } .......
和ContextClassLoader配合实现了一个线程中单例的“伪单例”模式,真正的亮点