Inject bean into enum

2019-01-13 15:02发布

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 ReportService from enum.

my service:

@Service
public class DataPrepareService {
    // my service
}

my enum:

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

I tried to use

@Autowired
DataPrepareService dataPrepareService;

, but it didn't work

How can I inject my service into enum?

8条回答
可以哭但决不认输i
2楼-- · 2019-01-13 15:08

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();
查看更多
Melony?
3楼-- · 2019-01-13 15:14
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);
        }
    }

[...]

}

weekens' answer works if you change inner class to static so spring can see it

查看更多
相关推荐>>
4楼-- · 2019-01-13 15:15

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"),
    ...
}
查看更多
你好瞎i
5楼-- · 2019-01-13 15:15

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!

查看更多
闹够了就滚
6楼-- · 2019-01-13 15:19

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());
查看更多
爷、活的狠高调
7楼-- · 2019-01-13 15:20

it will be hard to control that the spring container is already up and running at the time the enum is instantiated (if you had a variable with this type in a test-case, your container will usually not be there, even aspectj autowiring won't help there). i would recommend to just let the dataprepare-service or something give you the specific-params with a lookup-method with the enum-parameter.

查看更多
登录 后发表回答