J'ai le DataPrepareService qui prépare les données pour les rapports et j'ai un Enum avec des types de rapport et je dois injecter ReportService dans Enum ou avoir accès à ReportService à partir d'énum.
mon service:
@Service
public class DataPrepareService {
// my service
}
mon 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
}
}
J'ai essayé d'utiliser
@Autowired
DataPrepareService dataPrepareService;
, mais ça n'a pas marché
Comment puis-je injecter mon service dans enum?
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);
}
}
[...]
}
La réponse de weekens fonctionne si vous changez la classe intérieure en statique afin que le printemps puisse la voir
Peut-être quelque chose comme ça:
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"),
...
}
il sera difficile de contrôler que le conteneur de ressort est déjà opérationnel au moment de l'instanciation de l'énumération (si vous aviez une variable de ce type dans un scénario de test, votre conteneur ne serait généralement pas là, même si le gain de temps était atteint t aider là-bas). Je recommanderais simplement de laisser le service dataprepare ou quelque chose qui vous donne les paramètres spécifiques avec une méthode de recherche avec le paramètre enum.
Il existe une autre approche que vous voudrez peut-être explorer. Cependant, au lieu d’injecter une bean
dans enum
, il associe une bean
à une enum
Disons que vous avez un enum WidgetType
et 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;
}
}
Et vous voulez créer Widget
s de ce type en utilisant une usine BarFactory
ou 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;
}
}
La WidgetService
est l'endroit où la majeure partie du travail est effectuée. Ici, j'ai un simple champ AutoWired
qui garde une trace de tous les WidgetFactor
ies enregistrés. En tant qu’opération postConstruct
, nous créons une carte de l’énum et de l’usine associée.
Désormais, les clients peuvent injecter la classe WidgetService
et obtenir l’usine pour le type d’énum donné.
@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();
}
}
Peut-être que vous pouvez utiliser cette 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;
}
}
Et dans une autre classe dont vous avez besoin du haricot de l'énum:
ChartTypes plotType = ChartTypes.AreaChart
Object areaChartService = applicationContext.getBean(chartType.getServiceName());
Enum
s sont statiques, vous devez donc trouver un moyen d'accéder aux beans à partir d'un contexte statique.
Vous pouvez créer une classe nommée ApplicationContextProvider
qui implémente l'interface 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;
}
}
puis ajoutez ceci votre fichier de contexte d'application:
<bean id="applicationContextProvider" class="xxx.xxx.ApplicationContextProvider"></bean>
après cela, vous pouvez accéder au contexte de l'application de manière statique comme ceci:
ApplicationContext appContext = ApplicationContextProvider.getApplicationContext();
Je pense que ce dont tu as besoin
public enum MyEnum {
ONE,TWO,THREE;
}
Autowire l'énum comme d'habitude
@Configurable
public class MySpringConfiguredClass {
@Autowired
@Qualifier("mine")
private MyEnum myEnum;
}
Voici le truc, utilisez la méthode-usine = "valueOf" et assurez-vous également que Lazy-init = "false"
de sorte que le conteneur crée le haricot dès le départ
<bean id="mine" class="foo.bar.MyEnum" factory-method="valueOf" lazy-init="false">
<constructor-arg value="ONE" />
</bean>
et vous avez terminé!