Inject bean into enum

前端 未结 8 2027
误落风尘
误落风尘 2020-11-30 02:01

I have the DataPrepareService that prepare data for reports and I have an Enum with report types, and I need to inject ReportService into Enum or have access to ReportServic

相关标签:
8条回答
  • 2020-11-30 02:39

    I think this what you need

    public enum MyEnum {
        ONE,TWO,THREE;
    }
    

    Autowire the enum as per usual

    @Configurable
    public class MySpringConfiguredClass {
    
              @Autowired
          @Qualifier("mine")
              private MyEnum myEnum;
    
    }
    

    Here is the trick, use the factory-method="valueOf" and also make sure lazy-init="false"

    so the container creates the bean upfront

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

    and you are done!

    0 讨论(0)
  • 2020-11-30 02:40

    Maybe something like this:

    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"),
        ...
    }
    
    0 讨论(0)
  • 2020-11-30 02:41

    There is one another approach you may like to explore. However instead of injecting a bean into enum it associates a bean with an enum

    Say you have an enum WidgetType and Widget class

    public enum WidgetType {
      FOO, BAR;
    }
    
    public class Widget {
    
      WidgetType widgetType;
      String message;
    
      public Widget(WidgetType widgetType, String message) {
        this.widgetType = widgetType;
        this.message = message;
      }
    }
    

    And you want to create Widgets of this type using a Factory BarFactory or FooFactory

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

    The WidgetService is where most of the work happens. Here I have a simple AutoWired field which keeps tracks of all the registered WidgetFactories. As a postConstruct operation we create a map of the enum and the associated factory.

    Now clients could inject the WidgetService class and get the factory for the given enum type

    @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();
      }
    
    }
    
    0 讨论(0)
  • 2020-11-30 02:45

    Maybe you can use this solution ;

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

    And in another class which you need the bean of the Enum :

    ChartTypes plotType = ChartTypes.AreaChart
    Object areaChartService = applicationContext.getBean(chartType.getServiceName());
    
    0 讨论(0)
  • 2020-11-30 02:48

    Enums are static, so you have to figure out a way to access to the beans from a static context.

    You can create a class named ApplicationContextProvider that implements the ApplicationContextAware interface.

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

    then add this your application context file:

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

    after that you could access to the application context in a static way like this:

    ApplicationContext appContext = ApplicationContextProvider.getApplicationContext();
    
    0 讨论(0)
  • 2020-11-30 02:58

    Just pass it to the method manually

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

    As long as you call the method only from managed beans, you can inject it in these beans and pass the reference to the enum on each call.

    0 讨论(0)
提交回复
热议问题