2016-07-15 63 views
1

我想实现一个注释,它在应用程序启动后立即向工厂注册类(不是类的实例)。我正在使用Spring Framework 4.2.7。在Spring中实现自定义注释

考虑一个带有仪表板和多个小部件的系统。仪表板有一个配置文件,其中包含要显示给当前用户的小部件列表。显示时,它读取配置并创建小部件。小部件将从配置中接收其他参数。

下面是一些代码说明这一点:

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; 
} 

在实现我的小工具,我不想处理与工厂类注册小工具。理想的情况下我只想注释这样的小部件:

@DashboardWidget(id = "uniqueId") 
public class DashboardWidgetA implements DashboardWidget { 
    // ... 
} 

当应用程序启动时,它应该扫描类路径@DashboardWidget注释和与工厂登记类,从而使小部件可以通过给createWidget法来构建小部件的ID。

此刻我有点困惑。我认为Spring已经有了所有的工具来实现这种行为。但我想不出如何去做。

你有什么建议吗?

回答

1

没有什么能阻止你创建自定义注释:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
public @interface DashboardWidget {} 

然后你就可以注释你的Widget的课程,让他们的Spring beans。如果你想让它们作为单例(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; 
    } 
} 

所以这里大多是无关的春天,除了你刚才通过你的bean运行找到注释的。

+0

嘿伊戈尔,谢谢你指点我的应用程序事件。我会接受这个答案:) – gdiquest