Java 在Spring的运行时注册bean(原型)
只是需要社区的评估。下面是一段代码,这是一个创建特定类型实例的简单工厂。该方法将在上下文中将bean注册为原型并返回实例。这是我第一次在运行时配置bean。你能评价并提供反馈吗?先谢谢你Java 在Spring的运行时注册bean(原型),java,spring,spring-mvc,dependency-injection,Java,Spring,Spring Mvc,Dependency Injection,只是需要社区的评估。下面是一段代码,这是一个创建特定类型实例的简单工厂。该方法将在上下文中将bean注册为原型并返回实例。这是我第一次在运行时配置bean。你能评价并提供反馈吗?先谢谢你 package au.com.flexcontacts.flexoperations; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition
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 factory已在IoC容器中配置为单例。因此,要创建新的同步管理器,我需要执行以下操作:
flexSyncFactory.createSyncService(userName, password, SyncType.FULL);
我正在使用Spring3.1。请回顾并提供您的宝贵反馈
亲切问候。这纯粹是我的观点,不是专家的观点: Spring为应用程序上下文的定制修改提供了两种机制——使用它可以修改现有的bean定义或添加新的bean定义,还可以修改bean实例(围绕代理等进行包装) Spring不提供任何其他在运行时动态添加bean定义或bean实例的本机方法,但正如您所做的那样,获得底层bean工厂实例并添加bean定义是一种方法。这是可行的,但也有风险:
- 如果您用一个新类型覆盖一个现有的bean名称,会发生什么情况?这个bean已经被注入的地方是如何处理的。另外,如果一个现有的bean名称被完全不同的类型覆盖,会发生什么呢
- 这个新注册的bean没有任何自动连接的字段,也不会被注入到其他bean中——因此本质上,bean工厂只是作为保存bean的注册表,而不是真正的依赖项注入功能
- 如果在应用程序上下文上调用了
,那么支持bean工厂将被覆盖并创建一个新的工厂,因此直接注册到bean工厂的任何bean实例都将丢失refresh()
如果目标纯粹是创建由Spring自动连接的bean,我会选择类似的东西。如果上述风险可以接受,您的方法也应该有效 您的解决方案看起来不错。我相信我们也可以通过创建一个bean来实现BeanNameware和FactoryBean接口,然后在创建上下文之前设置值
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<String, Object> beans = new HashMap<String, Object>();
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;
}
}
公共类xxxxBean实现BeanNameware、FactoryBean{
publicstaticmapbeans=newhashmap();
私有字符串beanName;
@凌驾
public void setBeanName(字符串beanName){
this.beanName=beanName;
}
@凌驾
公共对象getObject(){
返回bean.get(beanName);
}
@凌驾
公共类getObjectType(){
返回beans.get(beanName.getClass();
}
@凌驾
公共布尔isSingleton(){
返回true;
}
}
这对我很有用:
声明一个专用的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
}
通过在XML配置文件中声明bean,让spring将该bean加载到其上下文中:
<bean id="appContext" class="my.package.MyContextWrapper">
</bean>
Bean是在会话作用域中创建的,并将存储在用户会话中。属性auto-wire-candidate告诉spring bean的依赖项(如setter、getter或构造函数参数)是否应该由spring自动处理。属性lazy init告诉Spring是否应该在需要时实例化这个bean
要获取SpringBean的句柄,请使用Spring应用程序上下文,如下所示:
Object bean=
getApplicationContext().getBean("dynamicBean");
if(bean instanceof MyBeanClass){
MyBeanClass myBean = (MyBeanClass) bean;
// do with the bean what ever you have to do.
}
我放弃了这种方法,因为我确实认为它有点冒险。我刚刚使用了简单工厂和反射来生成这些bean。这些bean实际上不需要在spring容器中注册。我还将研究@configuable注释。谢谢你评估我的方法。谢谢。@Biju Kunjummen我在春天乞讨,如果我错了,请纠正我。我提到这样一句话:
Spring不提供任何其他本机方式来在运行时动态添加bean定义或bean实例。关于允许您在运行时添加bean并在插件体系结构中使用的StaticApplicationContext
呢?参考资料中提到的自定义BeanDefinitionReader
又如何?
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);
Object bean=
getApplicationContext().getBean("dynamicBean");
if(bean instanceof MyBeanClass){
MyBeanClass myBean = (MyBeanClass) bean;
// do with the bean what ever you have to do.
}