Java 将 bean 注入枚举
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16318454/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Inject bean into enum
提问by Andrej Soroj
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.
我有 DataPrepareService 为报告准备数据,我有一个带有报告类型的 Enum,我需要将 ReportService 注入 Enum 或从枚举访问 ReportService。
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?
如何将我的服务注入枚举?
回答by weekens
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"),
...
}
回答by cproinger
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.
很难控制在枚举实例化时 spring 容器已经启动并运行(如果你在测试用例中有一个这种类型的变量,你的容器通常不会在那里,即使是aspectj自动装配也不会)在那里帮忙)。我建议只让 dataprepare-service 或其他东西为您提供带有枚举参数的查找方法的特定参数。
回答by user3195004
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' answerworks if you change inner class to static so spring can see it
如果您将内部类更改为静态以便 spring 可以看到它,那么weekens 的答案会起作用
回答by Josema
Enum
s are static, so you have to figure out a way to access to the beans from a static context.
Enum
s 是静态的,所以你必须想办法从静态上下文访问 bean。
You can create a class named ApplicationContextProvider
that implements the ApplicationContextAware
interface.
您可以创建一个名为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;
}
}
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();
回答by Ashish Shetkar
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"
这是诀窍,使用 factory-method="valueOf" 并确保 lazy-init="false"
so the container creates the bean upfront
所以容器预先创建了 bean
<bean id="mine" class="foo.bar.MyEnum" factory-method="valueOf" lazy-init="false">
<constructor-arg value="ONE" />
</bean>
and you are done!
你就完成了!
回答by Wanja Krah
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.
只要您仅从托管 bean 调用该方法,您就可以将其注入这些 bean 并在每次调用时传递对枚举的引用。
回答by diduknow
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
您可能想探索另一种方法。但是,不是将 abean
注入enum
其中,而是将abean
与enum
Say you have an enum WidgetType
and Widget
class
假设你有一个枚举WidgetType
和Widget
类
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 Widget
s of this type using a Factory BarFactory
or FooFactory
并且您想Widget
使用 FactoryBarFactory
或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 WidgetFactor
ies. As a postConstruct
operation we create a map of the enum and the associated factory.
这WidgetService
是大部分工作发生的地方。在这里,我有一个简单的AutoWired
字段,用于跟踪所有已注册的WidgetFactor
ies。作为postConstruct
操作,我们创建了枚举和关联工厂的映射。
Now clients could inject the WidgetService
class and get the factory for the given enum type
现在客户可以注入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();
}
}
回答by Ersoy Ko?ak
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 :
在另一个类中,您需要 Enum 的 bean:
ChartTypes plotType = ChartTypes.AreaChart
Object areaChartService = applicationContext.getBean(chartType.getServiceName());