如何在 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;
}
}
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;
}
}