首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态Spring bean创建

动态Spring bean创建
EN

Stack Overflow用户
提问于 2012-05-30 02:46:10
回答 2查看 7.1K关注 0票数 3

我使用的应用程序接口以XXXLocalServiceUtil类的形式公开服务,这些类是单例对象的静态包装器。我不想使用静态XXXLocalServiceUtil方法,而是希望注入XXXLocalService对象本身,以便在我的代码中直接使用它们,例如:

代码语言:javascript
复制
@Named
public class MyMailingService {        
    @Inject UserLocalService userService;

    public String mailUser(String email) {
       User user = userService.getUser(email);
       emailUser(user);
    }
}

并像这样配置我的applicationContext.xml

代码语言:javascript
复制
<beans ...>
    <bean class="x.y.z.UserLocalServiceUtil" factory-method="getService"/>
    <bean class="x.y.z.CompanyLocalServiceUtil" factory-method="getService"/>
    ...
</beans>

这个可以完美地工作。现在,我讨论的这个应用程序接口有大约100个这样的XXXLocalServiceUtil类,每个类都有自己的静态getService方法,该方法返回实际的服务。我不想在我的applicationContext.xml中列出所有这些服务,而是让Spring为我注入的每个XXXLocalService找到正确的XXXLocalServiceUtil类。因此,我需要的是某种动态bean工厂,它将为我完成工作,当然是在延迟加载的基础上。

有人知道如何轻松实现这一点吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-06-06 04:19:53

您可以使用GenericApplicationContext将bean动态加载到applicationContext以及在xml中声明的其余spring bean。下面是一个使用Reflections library实现的示例。

代码语言:javascript
复制
private static final Pattern SERVICE_UTIL_PATTERN = Pattern.compile(".*LocalServiceUtil.*");

public static void main(String[] args) {
    ConfigurationBuilder builder = new ConfigurationBuilder().addUrls(
            ClasspathHelper.forPackage("x.y.z"))
            .setScanners(new SubTypesScanner(false));
    Reflections reflections = new Reflections(builder);
    GenericApplicationContext applicationContext = new GenericApplicationContext();
    Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

    for (Class<? extends Object> serviceUtilClass : classes) {
        String className = serviceUtilClass.getName();

        if (SERVICE_UTIL_PATTERN.matcher(className).matches()) {
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClassName(className);
            beanDefinition.setFactoryMethodName("getService");
            beanDefinition.setLazyInit(true);

            String beanName = StringUtils.uncapitalize(serviceClass.getSimpleName().replace("Util", ""));
            applicationContext.registerBeanDefinition(beanName, beanDefinition);
        }
    }

    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(applicationContext);
    reader.loadBeanDefinitions("classpath:/applicationContext.xml");
    applicationContext.refresh();
}

Spring:要在web应用程序中使用它,您可以简单地扩展Spring并覆盖initBeanDefinitionReader方法,如下所示……

代码语言:javascript
复制
private static final Pattern SERVICE_UTIL_PATTERN = Pattern.compile(".*LocalServiceUtil.*");

@Override
protected void initBeanDefinitionReader(
        XmlBeanDefinitionReader beanDefinitionReader) {
    ConfigurationBuilder builder = new ConfigurationBuilder().addUrls(
            ClasspathHelper.forPackage("x.y.z"))
            .setScanners(new SubTypesScanner(false));
    Reflections reflections = new Reflections(builder);
    Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);
    BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

    for (Class<? extends Object> serviceClass : classes) {
        String className = serviceClass.getName();

        if (SERVICE_UTIL_PATTERN.matcher(className).matches()) {
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClassName(className);
            beanDefinition.setFactoryMethodName("getService");
            beanDefinition.setLazyInit(true);
            String beanName = StringUtils.uncapitalize(serviceClass
                    .getSimpleName().replace("Util", ""));
            registry.registerBeanDefinition(beanName, beanDefinition);
        }
    }
}

}

并将以下context-param添加到您的web.xml...

代码语言:javascript
复制
<context-param>
  <param-name>contextClass</param-name>
  <param-value>x.y.z.MyXmlWebApplicationContext</param-value>
</context-param>
票数 7
EN

Stack Overflow用户

发布于 2012-05-30 03:14:23

您可以尝试将@Inject更改为@Autowired,并在applicationContext.xml中定义为按类型自动布线,如下所示:

代码语言:javascript
复制
<beans ... default-autowire="byType">
    ...
</beans>

@Inject@Autowired是等价的,但是Spring的@Autowired注释的优点是需要强制注入所需的属性。

另一种解决方案:

您可以使用具有作用域prototype的beans,而不是使用工厂。

您的XXXLocalService必须实现ApplicationContextAware接口,并通过它获得原型bean,即:

代码语言:javascript
复制
@Named
public class MyMailingService implements ApplicationContextAware {        
    @Inject UserLocalService userService;

    private ApplicationContext appContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.appContext = applicationContext;
    }

    public String mailUser(String email) {
       User user = (User) appContext.getBean("user");
       emailUser(user);
    }
}

你的applicationContext.xml看起来像这样:

代码语言:javascript
复制
<beans ...>
    <bean id="user" class="x.y.z.User" scope="prototype"/>
    ...
</beans>

每次调用getBean()时,您都会获得该类型的一个新对象,其好处是将所有内容都注入到该bean中。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10804885

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档