如何定义继承自通用工厂的具体工厂bean在Spring中更优雅?

时间:2015-02-12 12:18:39

标签: spring generics configuration dependency-injection factory

Stackoverflow社区,

我目前定义了一个这样的通用工厂:

public class ResourceCrudServiceFactory<E, R extends ResourceSupport> implements FactoryBean<ResourceCrudService<R>> {

    private ObjectMapper mapper;
    private CrudService<E> entityCrudService;
    private BidirectionalResourceAssembler<E, R> assembler;

    @Override
    public ResourceCrudService<R> getObject()
            throws Exception {
        ResourceCrudServiceImpl<E, R> resourceCrudService = 
                new ResourceCrudServiceImpl<E, R>(); 
        resourceCrudService.setMapper(mapper);
        resourceCrudService.setService(entityCrudService);
        resourceCrudService.setAssembler(assembler);
        return resourceCrudService;
    }

    @Override
    public Class<?> getObjectType() {
        return ResourceCrudService.class;
    }

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

    @Autowired
    public void setMapper(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    public void setEntityCrudService(CrudService<E> entityCrudService) {
        this.entityCrudService = entityCrudService;
    }

    public void setAssembler(
            BidirectionalResourceAssembler<E, R> assembler) {
        this.assembler = assembler;
    }

}

为了创建工厂生产的具体表示,我目前将工厂子类化为例如此

@Component(value = "colorTypeResourceServiceFactory")
public class ColorTypeResourceServiceFactory extends ResourceCrudServiceFactory<ColorType, ColorTypeResource> {

    @Override
    @Autowired
    public void setEntityCrudService(CrudService<ColorType> entityCrudService) {
        super.setEntityCrudService(entityCrudService);
    }

    @Override
    @Autowired
    public void setAssembler(
            BidirectionalResourceAssembler<ColorType, ColorTypeResource> assembler) {
        super.setAssembler(assembler);
    }

}

如果我继续这样下去,我将最终得到像工厂的​​80个子类,只是为了创建接口的具体实现。有没有更优雅的方法来实现相同的,没有Spring DI中的所有子类开销?

祝你好运, 的Marius

1 个答案:

答案 0 :(得分:2)

好的,我找到了一个可能的解决方案:在@Configuration带注释的配置类中定义具体bean。 E.g:

@ComponentScan
@Configuration
@EnableHypermediaSupport(type = HypermediaType.HAL)
@EnableAutoConfiguration
@EnableJSONDoc
//@EnableWebMvc
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);
    }

    // LinkConverterService factories
    @Bean
    public LinkConverterService<ItemType> itemTypeLinkConverterServiceFactory(ApplicationContext context) {
        LinkConverterServiceImpl<ItemType> linkConverter = new LinkConverterServiceImpl<ItemType>();
        linkConverter.setService(context.getBean(ItemTypeServiceImpl.class));
        linkConverter.setAssembler(context.getBean(ItemTypeResourceAssembler.class));
        return linkConverter;
    }

    // Resource Crud Service factories
    @Bean
    public ResourceCrudServiceFactory<ColorType, ColorTypeResource> colorTypeResourceServiceFactory(ApplicationContext context) {
        ResourceCrudServiceFactory<ColorType, ColorTypeResource> service = new ResourceCrudServiceFactory<>();
        service.setAssembler(context.getBean(ColorTypeResourceAssembler.class));
        service.setEntityCrudService(context.getBean(ColorTypeServiceImpl.class));
        return service;
    }

    @Bean
    public ResourceCrudServiceFactory<ItemType, ItemTypeResource> itemTypeResourceServiceFactory(ApplicationContext context) {
        ResourceCrudServiceFactory<ItemType, ItemTypeResource> service = new ResourceCrudServiceFactory<>();
        service.setAssembler(context.getBean(ItemTypeResourceAssembler.class));
        service.setEntityCrudService(context.getBean(ItemTypeServiceImpl.class));
        return service;
    }

    @Bean
    public ResourceCrudServiceFactory<ColorFamily, ColorFamilyResource> colorFamilyResourceServiceFactory(ApplicationContext context) {
        ResourceCrudServiceFactory<ColorFamily, ColorFamilyResource> service = new ResourceCrudServiceFactory<>();
        service.setAssembler(context.getBean(ColorFamilyResourceAssembler.class));
        service.setEntityCrudService(context.getBean(ColorFamilyServiceImpl.class));
        return service;
    }

    @Bean
    public ResourceCrudServiceFactory<Item, ItemResource> itemResourceServiceFactory(ApplicationContext context) {
        ResourceCrudServiceFactory<Item, ItemResource> service = new ResourceCrudServiceFactory<>();
        service.setAssembler(context.getBean(ItemResourceAssembler.class));
        service.setEntityCrudService(context.getBean(ItemServiceImpl.class));
        return service;
    }

}