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配合实现了一个线程中单例的“伪单例”模式,真正的亮点

 

posted @ 2014-02-13 20:02  心意合一  阅读(1229)  评论(0编辑  收藏  举报