在 Spring 中实现自定义注释
Implement custom annotation in Spring
我想实现一个注释,在应用程序启动后立即向工厂注册 classes(不是 classes 的实例)。我正在使用 Spring Framework 4.2.7.
考虑一个带有仪表板和多个小部件的系统。仪表板有一个配置文件,其中包含要为当前用户显示的小部件列表。显示时,它会读取配置并创建小部件。小部件将从配置中接收其他参数。
这里有一段代码说明了这一点:
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;
}
在实现我的小部件时,我不想处理向工厂注册小部件的问题 class。理想情况下,我会像这样注释小部件:
@DashboardWidget(id = "uniqueId")
public class DashboardWidgetA implements DashboardWidget {
// ...
}
当应用程序启动时,它应该扫描 class 路径以查找 @DashboardWidget
注释并向工厂注册 classes,以便可以通过提供 createWidget 来构造小部件-method 小部件的id。
此刻我有点困惑。我认为 Spring 拥有实现此行为的所有工具。但是我想不出怎么做的方法。
你对我有什么建议吗?
没有什么能阻止您创建自定义注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DashboardWidget {}
然后您可以注释您的 Widget 的 类 并使它们成为 spring 个 bean。如果您想将它们作为单例 (scope=singleton) 或每个用户的单独实例 (scope=prototype),则必须牢记。
您必须实施:
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;
}
}
所以这里大部分与 spring 无关,除了你只是 运行 通过你的 bean 来找到带注释的 bean。
我想实现一个注释,在应用程序启动后立即向工厂注册 classes(不是 classes 的实例)。我正在使用 Spring Framework 4.2.7.
考虑一个带有仪表板和多个小部件的系统。仪表板有一个配置文件,其中包含要为当前用户显示的小部件列表。显示时,它会读取配置并创建小部件。小部件将从配置中接收其他参数。
这里有一段代码说明了这一点:
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;
}
在实现我的小部件时,我不想处理向工厂注册小部件的问题 class。理想情况下,我会像这样注释小部件:
@DashboardWidget(id = "uniqueId")
public class DashboardWidgetA implements DashboardWidget {
// ...
}
当应用程序启动时,它应该扫描 class 路径以查找 @DashboardWidget
注释并向工厂注册 classes,以便可以通过提供 createWidget 来构造小部件-method 小部件的id。
此刻我有点困惑。我认为 Spring 拥有实现此行为的所有工具。但是我想不出怎么做的方法。
你对我有什么建议吗?
没有什么能阻止您创建自定义注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DashboardWidget {}
然后您可以注释您的 Widget 的 类 并使它们成为 spring 个 bean。如果您想将它们作为单例 (scope=singleton) 或每个用户的单独实例 (scope=prototype),则必须牢记。
您必须实施:
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;
}
}
所以这里大部分与 spring 无关,除了你只是 运行 通过你的 bean 来找到带注释的 bean。