在Spring中运行时注册bean(原型)

只需要社区评估的东西。 以下是一段代码,它是一个创建特定类型实例的简单工厂。 该方法将在上下文中将bean注册为原型并返回实例。 这是我第一次在运行时配置bean。 你能评价并提供反馈意见吗? 先谢谢你。

package au.com.flexcontacts.flexoperations; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.AbstractApplicationContext; import au.com.flexcontacts.exceptions.SyncClassCreactionError; /** * @author khushroo.mistry * Class purpose: Simple Factory to create an * instance of SynchroniseContactsService and register it in the Spring IoC. */ public final class FLEXSyncFactory implements ApplicationContextAware { private static AbstractApplicationContext context; /** * @param username * @param password * @param syncType * @return the correct service class * @throws SyncClassCreactionError * The method registers the classes dynamically into the Spring IoC */ public final SynchroniseContactsService createSyncService(String username, String password, SyncType syncType) throws SyncClassCreactionError { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory(); try { //Register the bean in the IoC BeanDefinition bdb = new GenericBeanDefinition(); bdb.setBeanClassName(syncType.getClassName()); bdb.setScope("prototype"); ConstructorArgumentValues constructor = bdb.getConstructorArgumentValues(); constructor.addIndexedArgumentValue(0, username); constructor.addIndexedArgumentValue(1, password); beanFactory.registerBeanDefinition(syncType.getInstanceName(), bdb); //Return instance of bean return (SynchroniseContactsService) beanFactory.getBean(syncType.getInstanceName()); } catch (Exception e) { e.printStackTrace(); throw new SyncClassCreactionError("Error: Illegal Handler"); } } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = (AbstractApplicationContext) applicationContext; } } 

FLEX Sync工厂已在IoC容器中配置为单例。 因此,要创建新的同步管理器,请执行以下操作:

 flexSyncFactory.createSyncService(userName, password, SyncType.FULL); 

我使用的是Spring 3.1。 请查看并提供宝贵的反馈意见。

亲切的问候。

这纯粹是我的观点,不是专家观点:

Spring提供了两种自定义修改应用程序上下文的机制 – 使用允许修改现有bean定义或添加新bean定义的BeanFactoryPostProcessor ,以及允许修改bean实例(将它们包装在代理等周围)的BeanPostProcessors 。

Spring没有提供在运行时动态添加bean定义或bean实例的任何其他本机方式,但是就像你通过获取底层bean工厂实例并添加bean定义一样,这是一种方法。 它有效,但存在风险:

  • 如果用新类型覆盖现有bean名称会发生​​什么情况,如何处理已经注入此bean的位置。 此外,如果现有的bean名称被完全不同的类型覆盖会发生什么!

  • 这个新注册的bean不会自动装入任何字段,也不会注入其他bean – 所以bean工厂本质上只是作为一个注册表来保存bean,而不是真正的dependency injectionfunction!

  • 如果在应用程序上下文中调用了refresh()那么将覆盖辅助bean工厂并创建一个新的工厂,因此任何直接针对bean工厂注册的bean实例都将丢失。

如果目标纯粹是为了创建由Spring自动assembly的bean,我会选择像@Configurable这样的东西。 如果上述风险可以接受,您的方法也应该有效。

这对我有用: http : //random-thoughts-vortex.blogspot.com/2009/03/create-dynamically-spring-beans.html

声明一个专用的Spring上下文bean,它将实现ApplicationContextAware和BeanFactoryPostProcessor接口:

  public class MyContextWrapper implements ApplicationContextAware, BeanFactoryPostProcessor { private ApplicationContext appContext; private ConfigurableListableBeanFactory factory; public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { this.factory = factory; } public void setApplicationContext(ApplicationContext c) throws BeansException { this.appContext = c; } //setters and getters } 

让Spring通过在XML配置文件中声明bean来将此bean加载到它的上下文中:

   

现在可以通过引用它来将此bean加载到应用程序的任何其他bean中:

     

使用GenericBeanDefinition加载bean定义:

 BeanDefinitionRegistry registry = ((BeanDefinitionRegistry )factory); GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(MyBeanClass.class); beanDefinition.setLazyInit(false); beanDefinition.setAbstract(false); beanDefinition.setAutowireCandidate(true); beanDefinition.setScope("session"); registry.registerBeanDefinition("dynamicBean",beanDefinition); 

Bean在会话范围中创建,并将存储在用户会话中。 属性auto wire candidate告诉spring是否应该由Spring自动处理bean的依赖项,如setter或getter或构造函数参数。 属性lazy init告诉Spring是否应该在需要时实例化这个bean。

要获取Spring bean的句柄,请使用Spring应用程序上下文,如下所示:

 Object bean= getApplicationContext().getBean("dynamicBean"); if(bean instanceof MyBeanClass){ MyBeanClass myBean = (MyBeanClass) bean; // do with the bean what ever you have to do. } 

你的解决方案很好看 我相信我们也可以通过创建实现BeanNameAware和FactoryBean接口的bean来实现,然后在创建上下文之前设置该值。

 xxxxBean.beansByName.put("synTable", synTable); ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); assert externalDataSource == context.getBean("synTable"); 

这是Bean实现

 public class xxxxBean implements BeanNameAware, FactoryBean { public static Map beans = new HashMap(); private String beanName; @Override public void setBeanName(String beanName) { this.beanName = beanName; } @Override public Object getObject() { return beans.get(beanName); } @Override public Class getObjectType() { return beans.get(beanName).getClass(); } @Override public boolean isSingleton() { return true; } }