Вставить bean в перечисление
У меня есть DataPrepareService, который готовит данные для отчетов, и у меня есть Enum с типами отчетов, и мне нужно добавить ReportService в Enum или получить доступ к ReportService из перечисления.
мой сервис:
@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
}
}
Я попытался использовать
@Autowired
DataPrepareService dataPrepareService;
но это не сработало
Как я могу ввести свою службу в перечисление?
Ответы
Ответ 1
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);
}
}
[...]
}
Ответ на выходные работает, если вы меняете внутренний класс на статичный, чтобы spring его видна
Ответ 2
Возможно, что-то вроде этого:
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"),
...
}
Ответ 3
будет трудно контролировать, что контейнер spring уже запущен и запущен во время создания перечисления (если у вас была переменная с этим типом в тестовом случае, ваш контейнер, как правило, не будет там, даже aspectj autowiring там не поможет). я бы рекомендовал просто позволить службе dataprepare или что-то дать вам специфические параметры с помощью метода lookup с параметром enum.
Ответ 4
Есть еще один подход, который вы можете изучить. Однако вместо того, чтобы вводить bean
в enum
он связывает bean
с enum
Скажем, у вас есть класс WidgetType
и Widget
enum
public enum WidgetType {
FOO, BAR;
}
public class Widget {
WidgetType widgetType;
String message;
public Widget(WidgetType widgetType, String message) {
this.widgetType = widgetType;
this.message = message;
}
}
И вы хотите создать Widget
этого типа с помощью Factory BarFactory
или 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;
}
}
WidgetService
- это место, где происходит большая часть работы. Здесь у меня есть простое поле AutoWired
котором хранятся следы всех зарегистрированных WidgetFactor
. В качестве операции 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();
}
}
Ответ 5
Enum
являются статическими, поэтому вам нужно выяснить способ доступа к beans из статического контекста.
Вы можете создать класс с именем 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();
Ответ 6
Я думаю, что вам нужно
public enum MyEnum {
ONE,TWO,THREE;
}
Autowire enum как обычно
@Configurable
public class MySpringConfiguredClass {
@Autowired
@Qualifier("mine")
private MyEnum myEnum;
}
Вот трюк, используйте factory -method = "valueOf", а также убедитесь, что
ленивый-INIT = "ложь"
поэтому контейнер создает bean аванс
<bean id="mine" class="foo.bar.MyEnum" factory-method="valueOf" lazy-init="false">
<constructor-arg value="ONE" />
</bean>
и все готово!
Ответ 7
Возможно, вы можете использовать это решение;
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;
}
}
И в другом классе, который вам нужен bean of Enum:
ChartTypes plotType = ChartTypes.AreaChart
Object areaChartService = applicationContext.getBean(chartType.getServiceName());
Ответ 8
Просто передайте его методу вручную
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
}
}
До тех пор, пока вы вызываете метод только из управляемых компонентов, вы можете вставлять его в эти компоненты и передавать ссылку на перечисление для каждого вызова.