java-将bean注入枚举

我有为报表准备数据的DataPrepareService,并且我有一个具有报表类型的Enum,并且我需要将ReportService注入Enum或从枚举中访问ReportService。

我的服务:

@Service
public class DataPrepareService {
    // my service
}

我的枚举:

public enum ReportType {

    REPORT_1("name", "filename"),
    REPORT_2("name", "filename"),
    REPORT_3("name", "filename")

    public abstract Map<String, Object> getSpecificParams();

    public Map<String, Object> getCommonParams(){
        // some code that requires service
    }
}

我尝试使用

@Autowired
DataPrepareService dataPrepareService;

,但是没有用

如何将服务注入枚举?

8个解决方案
58 votes
public enum ReportType {

    REPORT_1("name", "filename"),
    REPORT_2("name", "filename");

    @Component
    public static class ReportTypeServiceInjector {
        @Autowired
        private DataPrepareService dataPrepareService;

        @PostConstruct
        public void postConstruct() {
            for (ReportType rt : EnumSet.allOf(ReportType.class))
               rt.setDataPrepareService(dataPrepareService);
        }
    }

[...]

}

如果您将内部课程更改为静态课程,那么周末的答案就可以工作,这样春季可以看到它

user3195004 answered 2020-01-14T14:07:03Z
11 votes

也许是这样的:

public enum ReportType {
    @Component
    public class ReportTypeServiceInjector {
        @Autowired
        private DataPrepareService dataPrepareService;

        @PostConstruct
        public void postConstruct() {
            for (ReportType rt : EnumSet.allOf(ReportType.class))
               rt.setDataPrepareService(dataPrepareService);
        }
    }

    REPORT_1("name", "filename"),
    REPORT_2("name", "filename"),
    ...
}
weekens answered 2020-01-14T14:07:23Z
2 votes

您可能想探索另一种方法。 但是,不是将bean注入WidgetService,而是将AutoWiredWidgetFactor相关联

假设您有一个枚举WidgetServiceAutoWired

public enum WidgetType {
  FOO, BAR;
}

public class Widget {

  WidgetType widgetType;
  String message;

  public Widget(WidgetType widgetType, String message) {
    this.widgetType = widgetType;
    this.message = message;
  }
}

并且您想使用Factory AutoWiredWidgetFactor创建这种类型的WidgetServices

public interface AbstractWidgetFactory {
  Widget createWidget();
  WidgetType factoryFor();
}

@Component
public class BarFactory implements AbstractWidgetFactory {
  @Override
  public Widget createWidget() {
    return new Widget(BAR, "A Foo Widget");
  }
  @Override
  public WidgetType factoryFor() {
    return BAR;
  }
}

@Component
public class FooFactory implements AbstractWidgetFactory {
  @Override
  public Widget createWidget() {
    return new Widget(FOO, "A Foo Widget");
  }
  @Override
  public WidgetType factoryFor() {
    return FOO;
  }
}

WidgetService是进行大部分工作的地方。 在这里,我有一个简单的AutoWired字段,该字段跟踪所有已注册的WidgetFactories。 作为postConstruct操作,我们创建了枚举和关联工厂的地图。

现在客户可以注入WidgetService类并为给定的枚举类型获取工厂

@Service
public class WidgetService {

  @Autowired
  List<AbstractWidgetFactory> widgetFactories;

  Map<WidgetType, AbstractWidgetFactory> factoryMap = new HashMap<>();

  @PostConstruct
  public void init() {
    widgetFactories.forEach(w -> {
      factoryMap.put(w.factoryFor(), w);
    });
  }

  public Widget getWidgetOfType(WidgetType widgetType) {
    return factoryMap.get(widgetType).createWidget();
  }

}
diduknow answered 2020-01-14T14:08:01Z
1 votes

实例化枚举时将很难控制spring容器已经启动并运行(如果您在测试用例中具有此类型的变量,则您的容器通常将不存在,即使AspectJ自动装配也不会成功) 不能帮助那里)。 我建议只让dataprepare-service或某些东西为您提供带有enum参数的查找方法的特定参数。

cproinger answered 2020-01-14T14:08:22Z
1 votes

ApplicationContextProvider是静态的,因此您必须找出一种从静态上下文访问Bean的方法。

您可以创建一个名为ApplicationContextProvider的类,该类实现ApplicationContextAware接口。

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ApplicationContextProvider implements ApplicationContextAware{

 private static ApplicationContext appContext = null;

 public static ApplicationContext getApplicationContext() {
   return appContext;
 }

 public void setApplicationContext(ApplicationContext appContext) throws BeansException {
   this.appContext = appContext;
 }
}

然后将其添加到您的应用程序上下文文件中:

<bean id="applicationContextProvider" class="xxx.xxx.ApplicationContextProvider"></bean>

之后,您可以像下面这样以静态方式访问应用程序上下文:

ApplicationContext appContext = ApplicationContextProvider.getApplicationContext();
Josema answered 2020-01-14T14:08:55Z
0 votes

我认为这是你需要的

public enum MyEnum {
    ONE,TWO,THREE;
}

按照常规方式自动连接枚举

@Configurable
public class MySpringConfiguredClass {

          @Autowired
      @Qualifier("mine")
          private MyEnum myEnum;

}

这是窍门,请使用factory-method =“ valueOf”并确保lazy-init =“ false”

所以容器先创建了bean

<bean id="mine" class="foo.bar.MyEnum" factory-method="valueOf" lazy-init="false">
    <constructor-arg value="ONE" />
</bean>

完成了!

Ashish Shetkar answered 2020-01-14T14:09:33Z
0 votes

也许您可以使用此解决方案;

public enum ChartTypes {
AREA_CHART("Area Chart", XYAreaChart.class),
BAR_CHART("Bar Chart", XYBarChart.class),

private String name;
private String serviceName;

ChartTypes(String name, Class clazz) {
    this.name = name;
    this.serviceName = clazz.getSimpleName();
}

public String getServiceName() {
    return serviceName;
}

@Override
public String toString() {
    return name;
}
}

在另一个类中,您需要Enum的bean:

ChartTypes plotType = ChartTypes.AreaChart
Object areaChartService = applicationContext.getBean(chartType.getServiceName());
Ersoy Koçak answered 2020-01-14T14:09:57Z
-1 votes

只需手动将其传递给方法

public enum ReportType {

    REPORT_1("name", "filename"),
    REPORT_2("name", "filename"),
    REPORT_3("name", "filename")

    public abstract Map<String, Object> getSpecificParams();

    public Map<String, Object> getCommonParams(DataPrepareService  dataPrepareService){
        // some code that requires service
    }
}

只要仅从托管Bean调用该方法,就可以将其注入这些Bean中,并在每次调用时将引用传递给枚举。

Wanja Krah answered 2020-01-14T14:10:22Z
translate from https://stackoverflow.com:/questions/16318454/inject-bean-into-enum