Implementieren Sie benutzerdefinierte Anmerkungen im Frühjahr
Ich möchte eine Annotation implementieren, die Klassen (keine Instanzen von Klassen) bei einer Factory registriert, sobald die Anwendung gestartet wird. Ich verwende Spring Framework 4.2.7.
Stellen Sie sich ein System mit einem Dashboard und mehreren Widgets vor. Das Dashboard verfügt über eine Konfigurationsdatei, die eine Liste von Widgets enthält, die für den aktuellen Benutzer angezeigt werden sollen. Wenn es angezeigt wird, liest es die Konfiguration und erstellt die Widgets. Die Widgets erhalten zusätzliche Parameter aus der Konfiguration.
Hier ist ein Code, der dies veranschaulicht:
public class TestDashboard implements Dashboard {
public void dashboardPreDisplay() {
List<String> widgets = getWidgetList(/* current user in session */);
for (String widgetId : widgets) {
// create instance of DashboardWidget with given ID
DashboardWidget x = widgetFactory.createWidget(widgetId);
}
}
public List<String> getWidgetList(String user) {
// load list of IDs of DashboardWidgets to be displayed for the user
}
@Autowired
private WidgetFactory widgetFactory;
}
@Service
public class WidgetFactory {
public DashboardWidget createWidget(String widgetId) {
// look up Class<> of DashboardWidget with given id in widgetClasses
// construct and initialize DashboardWidget
}
private HashMap<String, Class<?>> widgetClasses;
}
Bei der Implementierung meiner Widgets möchte ich mich nicht mit der Registrierung des Widgets bei der Factory-Klasse befassen. Im Idealfall würde ich das Widget einfach so kommentieren:
@DashboardWidget(id = "uniqueId")
public class DashboardWidgetA implements DashboardWidget {
// ...
}
Wenn die Anwendung gestartet wird, sollte sie den Klassenpfad nach @DashboardWidget
Anmerkungen durchsuchen und die Klassen bei der Factory registrieren, damit die Widgets erstellt werden können, indem der createWidget-Methode die ID des Widgets zugewiesen wird.
Im Moment bin ich etwas verwirrt. Ich denke, Spring hat jedes Werkzeug an Bord, um dieses Verhalten zu erreichen. Aber ich kann mir keinen Weg vorstellen, wie es geht.
Hast du einen Rat für mich?
Nichts hindert Sie daran, Ihre benutzerdefinierte Anmerkung zu erstellen:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DashboardWidget {}
Dann können Sie die Klassen Ihres Widgets mit Anmerkungen versehen und sie zu Frühlingsbohnen machen. Sie müssen berücksichtigen, ob Sie sie als Singletons (scope = singleton) oder als separate Instanzen pro Benutzer (scope = prototype) haben möchten.
Sie müssen implementieren:
public class WidgetInitializationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
String originalClassName = getOriginalClassName(beanDefinitionName, event);
if (originalClassName != null) {
Class<?> clazz = Class.forName(originalClassName);
if (hasWidgetAnnotation(clazz)) {
registerSomewhereYourWidget(context, beanDefinitionName, originalClassName);
}
}
}
}
private String getOriginalClassName(String name, ContextRefreshedEvent event) {
try {
ConfigurableListableBeanFactory factory =
(ConfigurableListableBeanFactory)event.getApplicationContext().getAutowireCapableBeanFactory();
BeanDefinition beanDefinition = factory.getBeanDefinition(name);
return beanDefinition.getBeanClassName();
} catch (NoSuchBeanDefinitionException e) {
LOG.debug("Can't get bean definition for : " + name);
return null;
}
}
Meistens hat hier also nichts mit Frühling zu tun, außer dass Sie nur durch Ihre Bohnen laufen, um kommentierte zu finden.