2014-09-22 58 views
1

我有下面的代码片断获取区域(顶部或左侧)的所有可用菜单项,并添加用户有权访问ArrayList集合的小部件。现在,getWidgetsByZone(zone)返回64个项目并遍历它们。我在这种方法中看到一些性能滞后(在一个名为GlowRoot的工具中,它记录每个用户操作的时间跟踪)我不知道为什么。我试图通过切换到其他最佳收集来提高性能。有人可以帮我选择适合我的场景的最佳收藏吗?使用JDK 7Java集合为最佳性能

AM,休眠3.6和Spring 3.1

这里是getWidgetsByZone的DashboardService.getMenuItems()实现

public List<IContentWidget> getMenuItems(String zone) { 
     List<IContentWidget> widgets = new ArrayList<IContentWidget>(); 
     if (zone != null) { 

      List<IPersistentEntityInstance> instances = getWidgetsByZone(zone); 

      for (IPersistentEntityInstance instance : instances) { 
       IContentWidget contentWidget = (IContentWidget) instance; 
       if (contentWidget.getZones() == null) continue; 

       // block widgets that should only show up in mobile/responsive ui 
       if (contentWidget.getZones().contains(RESPONSIVE_VISIBLE)) continue; 

       // Add widget only if the current user has read permission on the entity. 
       if (contentWidget.getTargetItemScreen() != null || contentWidget.getTargetListScreen() != null) { 
        if (isAccessible(contentWidget)) { 
         widgets.add(contentWidget); 
        } 
       } 
       else { 
        widgets.add(contentWidget); 
       } 
      } 
     } 
     Collections.sort(widgets, new Comparator<IContentWidget>() { 

      public int compare(IContentWidget o1, IContentWidget o2) { 
       int i = o1.getOrderNum() - o2.getOrderNum(); 
       return i == 0 ? 0 : i < 0 ? -1 : 1; 
      } 

     }); 
     return widgets; 
    } 

DashboardService.isAccesible()的执行情况

private boolean isAccessible(IContentWidget contentWidget) { 
    boolean isWidgetAccessible = false; 
    String permission = contentWidget.getDisplayPermission(); 
    if (permission != null) { 
     isWidgetAccessible = authorizationService.userHasPermission(SecurityHelper.getAuthenticatedUser(), 
       permission); 
    } 
    else { 
     IBaseScreen screen = contentWidget.getTargetItemScreen() == null ? contentWidget.getTargetListScreen() 
       : contentWidget.getTargetItemScreen(); 
     // return true when target screen is 'null', this means that target link cannot be secured because it is not 
     // associated with any entity 
     if (screen == null) { 
      isWidgetAccessible = true; 
     } 
     else { 
      IAccessEntry access = authorizationService.getAccessForEntityMetadata(screen.getEntityMetadata()); 

      // fetching metadata from entityMetadataService again to trigger population of facade 
      if (screen instanceof IListScreen && access.getIsReadable()) { 
       isWidgetAccessible = true; 
      } 
      else if (screen instanceof IItemScreen && access.getIsCreatable()) { 
       isWidgetAccessible = true; 
      } 
     } 
    } 
    return isWidgetAccessible; 
} 

实施方法

public List<IPersistentEntityInstance> getWidgetsByZone(String zone) { 
    IEntityMetadata entity = entityService.findEntityMetadataByName(ContentWidget.class.getSimpleName()); 
return entityService.runNamedQuery(entity, NamedQueryList.WIDGETS_BY_ZONE, new Object[] { zone }); 
    } 

这里是我的ContentWidget实体

@LocalOnly 
@Entity 
@EntityMetadataDefaults(editable = false) 
@Audited 
@NamedQueries({ 
    @NamedQuery(name = NamedQueryList.DASHBOARD_WIDGETS, query = "from ContentWidget where zones like '%dashboard%' and dashboardContexts.size = 0 order by orderNum", hints = { 
      @QueryHint(name = "org.hibernate.cacheable", value = "true"), 
      @QueryHint(name = "org.hibernate.cacheRegion", value = "Metadata") }), 
    @NamedQuery(name = NamedQueryList.WIDGETS_BY_ZONE, query = "from ContentWidget where zones like '%' || ? || '%' order by orderNum", hints = { 
      @QueryHint(name = "org.hibernate.cacheable", value = "true"), 
      @QueryHint(name = "org.hibernate.cacheRegion", value = "Metadata") }), 
    @NamedQuery(name = NamedQueryList.WIDGETS_BY_ZONE_ORDER_BY_NAME, query = "from ContentWidget where zones like '%' || ? || '%' order by displayName", hints = { 
      @QueryHint(name = "org.hibernate.cacheable", value = "true"), 
      @QueryHint(name = "org.hibernate.cacheRegion", value = "Metadata") }), 
    @NamedQuery(name = NamedQueryList.WIDGETS_BY_DASHBOARD_URL, query = "from ContentWidget where dashboardUrl like ? || '%'", hints = { 
      @QueryHint(name = "org.hibernate.cacheable", value = "true"), 
      @QueryHint(name = "org.hibernate.cacheRegion", value = "Metadata") }), 
    @NamedQuery(name = NamedQueryList.WIDGETS_BY_NAME, query = "from ContentWidget where name = ?", hints = { 
      @QueryHint(name = "org.hibernate.cacheable", value = "true"), 
      @QueryHint(name = "org.hibernate.cacheRegion", value = "Metadata") }), 
    @NamedQuery(name = NamedQueryList.WIDGETS_BY_CONTEXT, query = "from ContentWidget where zones like '%dashboard%' and ? in elements(dashboardContexts) order by orderNum", hints = { 
      @QueryHint(name = "org.hibernate.cacheable", value = "true"), 
      @QueryHint(name = "org.hibernate.cacheRegion", value = "Metadata") }) }) 
@Cacheable 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "Metadata") 
@EventDefaults({ 
     @EventHandlerDefaults(beanName = "contentWidgetPermissionCommand", eventType = EventTypeEnum.OnBeforeCreate), 
     @EventHandlerDefaults(beanName = "contentWidgetPermissionCommand", eventType = EventTypeEnum.OnBeforeUpdate) }) 
@ReadPermission(name = AuthorizationService.ANONYMOUS_PERMISSION) 
public class ContentWidget implements IContentWidget { 
    private static final long  serialVersionUID = 1680304771254400928L; 
    private String     packageGuid; 
    private Long     id; 

    private String     name;         // unique name to reconcile imported data 
    private String     displayName;       // used by UI 
    private String     description;       // anchor title attribute 
    private int      orderNum;        // universal ordering 
    private String     zones;         // csv: "top,left,dashboard,context,..." 
    private String     iconClass; 
    private String     displayPermission; 

    // menu settings 
    private IContentWidget   parent; 

    private String     targetUrl; 

    private IListScreen    targetListScreen; 
    private IItemScreen    targetItemScreen; 
    private boolean     isCacheable; 
    private boolean     isDivider; 

    private boolean     isPopup; 

    private List<IEntityMetadata> contextEntities;      // for contextual menus 
    protected IFilterDefinition  entityFilterDefinition; 
    // dashboard settings 
    private int      dashboardWidth = 1; 
    private String     dashboardUrl; 
    private String     dashboardWidgetType; 
    private IListScreen    dashboardListScreen; 
    private IItemScreen    dashboardItemScreen; 
    private List<IEntityMetadata> dashboardContexts;      // for item screen dashboards 

    private ISessionService   sessionService; 
    @Autowired 
    private IPassportContextService passportContextService; 
    @Autowired 
    private IReportingConfiguration reportingConfiguration; 
    private Timestamp    createdAt; 
    private Timestamp    updatedAt; 
    private ICustomNamedQuery  menuCountQuery; 
    private Set<IPassportContext> passportContexts; 
    } 

性能跟踪更新:

在GlowRoot的方法表现轨迹如下

60.0% com.dc.core.presentation.presenter.impl.WebContentPresenter.getMenuHTML(WebContentPresenter.java:435) 
50.0% com.dc.core.presentation.service.impl.DashboardService.getMenuItems(DashboardService.java:258) 
30.0% com.dc.core.presentation.service.impl.DashboardService.isAccessible(DashboardService.java:382) 

这里是我的WebContentPresenter.getMenuHTML()实现

public String getMenuHTML(String baseUrl, String zone, String cssClass, IPersistentEntityInstance entityInstance) { 
    (line 435) List<IContentWidget> instances = dashboardService.getMenuItems(zone); 
    StringBuffer html = new StringBuffer(); 

    if (instances == null || instances.isEmpty()) { 
     html.append("&nbsp;"); 
    } 
    else { 
     Map<Long, List<IContentWidget>> treeData = new HashMap<Long, List<IContentWidget>>(); 
     for (IContentWidget instance : instances) { 
      BeanWrapperImpl bean = new BeanWrapperImpl(instance); 
      Object parent = bean.getPropertyValue("parent"); 
      Long parentId = -1L; 
      if (passportContextService.getIsInContext(instance)) { 
       if (parent != null) { 
        parentId = ((IContentWidget) parent).getId(); 
       } 
       List<IContentWidget> children = treeData.get(parentId); 
       if (children == null) { 
        children = new ArrayList<IContentWidget>(); 
       } 
       children.add(instance); 
       treeData.put(parentId, children); 
      } 
     } 

     generateTreeHtml(html, treeData, -1L, baseUrl, "parent", entityInstance, 
       authorizationService.userHasAdminPermission(SecurityHelper.getAuthenticatedUser())); 
    } 
    return String.format("<ul class=\"%s\">%s</ul>", cssClass, html.toString()); 
} 
+0

为什么最后调用sort?数据库查询getWidgetsByZone()方法是否可以返回已经排序的结果? – SJha 2014-09-22 20:34:07

+2

“比较器”只要求你返回一个负数,一个正数,或者返回小于,大于或等于零。你不必在你的return语句中执行三元操作,因为无论如何它都会被两个数字的差别所覆盖。 – Makoto 2014-09-22 20:34:11

+2

此问题似乎无关紧要,因为它要求进行代码审查。 – 2014-09-22 20:34:12

回答

1

对于代码的可读性,我更喜欢:

public List<IContentWidget> getMenuItems(String zone) { 
    if(zone == null){ 
     return Collections. <IContentWidget> emptyList(); 
    } 
    List<IContentWidget> widgets = new ArrayList<IContentWidget>(); 
    List<IPersistentEntityInstance> instances = getWidgetsByZone(zone); 
    for (IPersistentEntityInstance instance : instances) { 
     IContentWidget contentWidget = (IContentWidget) instance; 
     if (contentWidget.getZones() == null || contentWidget.getZones().contains(RESPONSIVE_VISIBLE)) { 
      continue; 
     } 
     // Add widget only if the current user has read permission on the entity. 
     if (contentWidget.getTargetItemScreen() == null || 
      contentWidget.getTargetListScreen()== null) { 
      widgets.add(contentWidget);continue; 
     } 
     if (isAccessible(contentWidget)) { 
      widgets.add(contentWidget); 
     } 


    } 
} 
Collections.sort(widgets, new Comparator<IContentWidget>() { 

    public int compare(IContentWidget o1, IContentWidget o2) { 
     return o1.getOrderNum() - o2.getOrderNum(); 
    } 

}); 
return widgets; 
} 

而且改变

private boolean isAccessible(IContentWidget contentWidget) { 
    boolean isWidgetAccessible = false; 
    String permission = contentWidget.getDisplayPermission(); 
    if (permission != null) { 
     return authorizationService.userHasPermission(SecurityHelper.getAuthenticatedUser(), 
       permission); 
    } 
    else { 
     IBaseScreen screen = contentWidget.getTargetItemScreen() == null ? contentWidget.getTargetListScreen() 
       : contentWidget.getTargetItemScreen(); 
     // return true when target screen is 'null', this means that target link cannot be secured because it is not 
     // associated with any entity 
     if (screen == null) { 
      return true; 
     } 
     else { 
      IAccessEntry access = authorizationService.getAccessForEntityMetadata(screen.getEntityMetadata()); 

      // fetching metadata from entityMetadataService again to trigger population of facade 
      if (screen instanceof IListScreen && access.getIsReadable()) { 
       isWidgetAccessible = true; 
      } 
      else if (screen instanceof IItemScreen && access.getIsCreatable()) { 
       isWidgetAccessible = true; 
      } 
     } 
    } 
    return isWidgetAccessible; 
} 
2

对于64项集合之间的差别并不显著。我宁愿调查IContentWidget方法调用。你如何得到这些实例? 也许每次您调用getter时,都会执行对数据库的查询?你能提供一些关于持久层的更多细节吗?