package org.hotswap.agent.plugin.spring.getbean; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.hotswap.agent.logging.AgentLogger; /** * * Loadable detachable Spring bean holder * * @author Erki Ehtla * */ public class DetachableBeanHolder { private Object bean; private Object beanFactory; private Class<?>[] paramClasses; private Object[] paramValues; private static List<WeakReference<DetachableBeanHolder>> beanProxies = Collections .synchronizedList(new ArrayList<WeakReference<DetachableBeanHolder>>()); private static AgentLogger LOGGER = AgentLogger.getLogger(DetachableBeanHolder.class); /** * * @param bean * Spring Bean this object holds * @param beanFactry * Spring factory that produced the bean with a ProxyReplacer.FACTORY_METHOD_NAME method * @param paramClasses * @param paramValues */ public DetachableBeanHolder(Object bean, Object beanFactry, Class<?>[] paramClasses, Object[] paramValues) { this.bean = bean; this.beanFactory = beanFactry; this.paramClasses = paramClasses; this.paramValues = paramValues; beanProxies.add(new WeakReference<DetachableBeanHolder>(this)); } /** * Clears the bean references inside all of the proxies */ public static void detachBeans() { int i = 0; synchronized (beanProxies) { while (i < beanProxies.size()) { DetachableBeanHolder beanHolder = beanProxies.get(i).get(); if (beanHolder != null) { beanHolder.detach(); i++; } else { beanProxies.remove(i); } } } if (i > 0) { LOGGER.info("{} Spring proxies reset", i); } else { LOGGER.debug("No spring proxies reset"); } } /** * Clear the bean for this proxy */ public void detach() { bean = null; } /** * Returns an existing bean instance or retrieves and stores new bean from the Spring BeanFactory * * @return Bean this instance holds * @throws IllegalAccessException * @throws InvocationTargetException */ public Object getBean() throws IllegalAccessException, InvocationTargetException { Object beanCopy = bean; if (beanCopy == null) { Method[] methods = beanFactory.getClass().getMethods(); for (Method factoryMethod : methods) { if (ProxyReplacer.FACTORY_METHOD_NAME.equals(factoryMethod.getName()) && Arrays.equals(factoryMethod.getParameterTypes(), paramClasses)) { bean = factoryMethod.invoke(beanFactory, paramValues); beanCopy = bean; LOGGER.info("Bean '{}' loaded", bean.getClass().getName()); break; } } } return beanCopy; } protected boolean isBeanLoaded(){ return bean != null; } }