在另一个实例变量中使用自动装配的参数

时间:2018-11-08 02:10:10

标签: java spring autowired

我有一个实现接口的服务。现在,我想编写一个映射器,基本上就是说,当我传入此枚举类型时,请使用该服务。这就是我所拥有的

@Service
MyService implements Service {}


@Component
@RequiredArgsConstructor
MyMapper implements Mapper<Enum, Service> {

  private final MyService myService;

  private ImmutableMap<Enum, Service> MAPPER = ImmutableMap.<MyEnum, MyService>builder()
            .put(Enum.A, myService)
            .build();;

  @Override
  public Service map(Enum input) {
    return MAPPER.get(input);
  }
}

但是,这似乎不起作用。我认为我不允许使用(自动装配的)实例变量来实例化另一个实例变量。

为了解决这个问题,我现在使用单例模式。

@Service
MyService implements Service {}


@Component
@RequiredArgsConstructor
MyMapper implements Mapper<Enum, Service> {

  private final MyService myService;

  private ImmutableMap<Enum, Service> MAPPER = null;

  @Override
  public Service map(Enum input) {
    if(MAPPER == null){
      MAPPER = createMapper();
    }
    return MAPPER.get(input);
  }

  private ImmutableMap<Enum, Service> createMapper(){
    return ImmutableMap.<MyEnum, MyService>builder()
            .put(Enum.A, myService)
            .build();;
  }
}

这似乎可行,但是我想知道是否还有其他解决方案。

2 个答案:

答案 0 :(得分:1)

您正在遇到有关最终变量的极端情况;即使已将其标记为final,该映射的初始化程序语句也会在实例初始化程序块(否则会很有用)之前运行,而该实例初始化程序块将在为变量赋值的构造函数主体之前运行。

我不确定为什么要创建一个仅包含单例值的映射,但是您需要在构造函数体内分配该映射。如果您出于某些原因确实想要此设置,我的建议是:

private final Map<Enum, Service> MAPPER;

public MyMapper(MyService myService) {
    MAPPER = Map.of(Enum.A, myService);
}

答案 1 :(得分:1)

最适合此问题的服务定位器。

我的枚举:-

public enum MyEnum {
    A,
    B
}

创建服务并使用名称“ A”和“ B”(您的枚举的名称为字符串):-

 @Service("A")
 MyService1 implements Service {}

 @Service("B")
 MyService2 implements Service {}

创建MyMapper界面:-

public interface MyMapper {

    Service map(MyEnum myEnum);

}

配置ServiceLocatorFactoryBean:-

@Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean(){
    ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
    bean.setServiceLocatorInterface(MyMapper.class);
    return bean;
}

开始使用:-

@Autowired
MyMapper mapper;