BeanCopier from cglib is a capable tool for copying properties between beans, but calling BeanCopier.create every time you need a copy can become expensive. In a path that runs often, those repeated creations consume resources and can drag down server performance. The utility below addresses that by keeping created copiers in a cache and reusing them when the same source and target types appear again.

The cache is a static ConcurrentHashMap keyed by the source and target class names. When copy is called, the utility builds the key, checks the map, and either retrieves the existing BeanCopier or creates a new one and stores it. The actual property copy then runs through the cached instance. Because the map is concurrent, the utility can be shared across threads.

import org.springframework.cglib.beans.BeanCopier;

import java.util.concurrent.ConcurrentHashMap;

/**
 * BeanCopier utility class
 */
public class BeanCopierUtil {
    /**
     * Cache for BeanCopier instances
     */
    static final ConcurrentHashMap<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();

    /**
     * Copy with BeanCopier
     * @param source source object
     * @param target target object
     */
    public static void copy(Object source, Object target) {
        String key = genKey(source.getClass(), target.getClass());
        BeanCopier beanCopier;
        if (BEAN_COPIER_CACHE.containsKey(key)) {
            beanCopier = BEAN_COPIER_CACHE.get(key);
        } else {
            beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIER_CACHE.put(key, beanCopier);
        }
        beanCopier.copy(source, target, null);
    }

    /**
     * Generate cache key
     * @param srcClazz source class
     * @param tgtClazz target class
     * @return string
     */
    private static String genKey(Class<?> srcClazz, Class<?> tgtClazz) {
        return srcClazz.getName() + tgtClazz.getName();
    }
}

The implementation is intentionally small. The false argument in BeanCopier.create disables converter usage, and the null passed to copy matches that setup, so this works for ordinary property copying where no custom conversion is involved. The key combines the source and target class names, which is enough to distinguish the pairs this utility handles.

The benefit appears when the same pair of bean types is copied frequently. Instead of creating a BeanCopier for every operation, the first call creates it and later calls reuse it from the map. That turns repeated creation into a lookup, while the copy itself remains the same.

If an application copies objects only occasionally, the cache adds little. But in code paths that map beans repeatedly, this small wrapper keeps BeanCopier's copying ability while removing a costly repeated setup step.