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

How to define concrete factory beans inheriting from generic factory more elegant in Spring?

Whosebug 社区,

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

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 中的所有子类开销?

此致, 马吕斯

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

@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;
    }

}