Spring @Autowiring与通用工厂制造的bean

Bra*_*ugh 10 spring spring-mvc autowired

我有一组具有复杂初始化方案的类.基本上,我从我需要的接口开始,然后进行一堆调用,最后得到一个实现该接口的对象.

为了处理这个问题,我创建了一个工厂类,它可以在给定接口的情况下生成最终对象.我把这个工厂变成了一个bean,在XML中我指定我的各种服务bean通过这个工厂对象实例化,并带有一个他们将实现的接口参数.

这很好用,我完全得到了我需要的豆子.不幸的是,我想从我的控制器类访问它们,这些类是通过组件扫描发现的.我在这里使用@Autowired,看起来Spring不知道这些是什么类型的对象,并且由于@Autowired按类型工作,我是SOL.

在这里使用@Resource(name ="beanName")可以很好地工作,但是对于某些bean使用@Resource而对其他bean使用@Autowired似乎很奇怪.

有没有办法让Spring知道工厂将为每个bean创建哪个接口而不为每种类型设置不同的工厂方法?

顺便说一句,我正在使用Spring 2.5.6,否则我只是JavaConfig而忘记了它.

工厂类:

<T extends Client> T buildService(Class<T> clientClass) {
  //Do lots of stuff with client class and return an object of clientClass.
}
Run Code Online (Sandbox Code Playgroud)

应用上下文:

<bean id="serviceFactoryBean" class="com.captainAwesomePants.FancyFactory" />
<bean id="userService" factory-bean="serviceFactoryBean" factory-method="buildService">
   <constructor-arg value="com.captain.services.UserServiceInterface" />
</bean>
<bean id="scoreService" factory-bean="serviceFactoryBean" factory-method="buildService">
   <constructor-arg value="com.captain.services.ScoreServiceInterface" />
</bean>  
Run Code Online (Sandbox Code Playgroud)

我的控制器:

public class HomepageController {

   //This doesn't work
   @Autowired @Qualifier("userService") UserServiceInterface userService;

   //This does
   @Resource(name="scoreService") ScoreServiceInterface scoreService;
}
Run Code Online (Sandbox Code Playgroud)

ska*_*man 8

我建议你进一步采用工厂模式,将工厂实现为Spring FactoryBean.该FactoryBean接口有一个getObjectType()方法,包含调用以发现工厂将返回的类型.只要您的工厂返回合理的价值,这就可以让您自动装配一些东西.


ree*_*ees 5

我遇到了类似的问题,但对我来说,我想使用单个工厂来创建使用JMockit(我需要使用的测试框架)的自动连接依赖项的模拟实现.

在找到令人满意的互联网解决方案后,我把一个简单的解决方案整合在一起,对我来说非常有用.

我的解决方案也使用Spring FactoryBean,但它只使用一个工厂bean来创建我的所有bean(最初的提问者似乎希望这样做).

我的解决方案是实现一个工厂工厂的元工厂,为FactoryBean真正的单一工厂提供包装.

这是我的JMockit mock bean工厂的Java:

public class MockBeanFactory<C> implements FactoryBean<C> {

    private Class<C> mockBeanType;
    protected MockBeanFactory(){}

    protected  <C> C create(Class<C> mockClass) {
        return Mockit.newEmptyProxy(mockClass);
    }

    @Override
    public C getObject() throws Exception {
        return create(mockBeanType);
    }

    @Override
    public Class<C> getObjectType() {
        return mockBeanType;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class MetaFactory {
        public <C> MockBeanFactory<C> createFactory(Class<C> mockBeanType) {
            MockBeanFactory<C> factory = new MockBeanFactory<C>();
            factory.mockBeanType = mockBeanType;
            return factory;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在Spring上下文XML文件中,您只需创建创建特定bean类型工厂的元工厂:

<bean id="metaFactory" class="com.stackoverflow.MockBeanFactory$MetaFactory"/>

<bean factory-bean="metaFactory" factory-method="createFactory">
    <constructor-arg name="mockBeanType" value="com.stackoverflow.YourService"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

为了使这个工作适用于原始提问者的情况,可以调整它来制作FactoryBeans包装/适配器serviceFactoryBean:

public class FancyFactoryAdapter<C> implements FactoryBean<C> {

    private Class<C> clientClass;
    private FancyFactory serviceFactoryBean;

    protected FancyFactoryAdapter(){}

    @Override
    public C getObject() throws Exception {
        return serviceFactoryBean.buildService(clientClass);
    }

    @Override
    public Class<C> getObjectType() {
        return clientClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class MetaFactory {

        @Autowired FancyFactory serviceFactoryBean;

        public <C> FancyFactoryAdapter<C> createFactory(Class<C> clientClass) {
            FancyFactoryAdapter<C> factory = new FancyFactoryAdapter<C>();
            factory.clientClass = clientClass;
            factory.serviceFactoryBean = serviceFactoryBean;
            return factory;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在XML中(请注意,只有使用userServiceFactoryid和userServicebean id才能使用@Qualifier注释):

<bean id="metaFactory" class="com.stackoverflow.FancyFactoryAdapter$MetaFactory"/>

<bean id="userServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
    <constructor-arg name="clientClass" value="com.captain.services.UserServiceInterface"/>
</bean>

<bean id="userService" factory-bean="userServiceFactory"/>

<bean id="scoreServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
    <constructor-arg name="clientClass" value="com.captain.services.ScoreServiceInterface"/>
</bean>

<bean id="scoreService" factory-bean="scoreServiceFactory"/>
Run Code Online (Sandbox Code Playgroud)

就是这样,只需要一个小的Java类和一个简单的样板配置,你的自定义bean工厂就可以创建所有的bean并让Spring成功解决它们.

  • 我赞成这一点主要是因为这是Java,因此FactoryFactory对象始终是正确的! (2认同)