2016-07-15 105 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