Liferay 启动过程分析6-初始化Portlets

 在MainServlet中,初始化插件包之后,就开始初始化Portlets:

对应的代码是:

  
  
  
  
  1. if (_log.isDebugEnabled()) { 
  2.             _log.debug("Initialize portlets"); 
  3.         } 
  4.  
  5.         List<Portlet> portlets = null
  6.  
  7.         try { 
  8.             portlets = initPortlets(pluginPackage); 
  9.         } 
  10. ... 

 

它会去调用initPortlets方法,并且传入一个我们上一步刚初始化的核心pluginPackage,我们来细看它究竟做了哪些事情:

 

读取配置文件:

首先,它去取得servletContext,然后获取一组xml配置文件:

  
  
  
  
  1. protected List<Portlet> initPortlets(PluginPackage pluginPackage) 
  2.         throws Exception { 
  3.  
  4.         ServletContext servletContext = getServletContext(); 
  5.  
  6.         String[] xmls = new String[] { 
  7.             HttpUtil.URLtoString( 
  8.                 servletContext.getResource( 
  9.                     "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)), 
  10.             HttpUtil.URLtoString( 
  11.                 servletContext.getResource("/WEB-INF/portlet-ext.xml")), 
  12.             HttpUtil.URLtoString( 
  13.                 servletContext.getResource("/WEB-INF/liferay-portlet.xml")), 
  14.             HttpUtil.URLtoString( 
  15.                 servletContext.getResource("/WEB-INF/liferay-portlet-ext.xml")), 
  16.             HttpUtil.URLtoString( 
  17.                 servletContext.getResource("/WEB-INF/web.xml")) 
  18.         }; 
  19. .... 

这些xml配置文件中,我研究了下,大概是提供如下的功能。

portlet_custom.xml可以用来根据请求的p_p_id字段,到这个文件中找到相应的portlet的<init-param>的<view-action>元素,然后去struts-config.xml中找到action的配置信息,最终到tiles-config.xml中找到对应的页面信息。

portlet-ext.xml,定义了portlet的初始化信息。

liferay-portlet.xml,定义了portlet在liferay框架中的一般外观信息

liferay-portlet-ext.xml,定义了portlet在liferay框架中的模板和是否允许重复。

 

初始化EAR:

然后,调用以下代码来初始化:

  
  
  
  
  1. PortletLocalServiceUtil.initEAR(servletContext, xmls, pluginPackage); 

它最终会调用PortletLocalServiceImpl的initEAR方法:

  
  
  
  
  1. public void initEAR( 
  2.         ServletContext servletContext, String[] xmls, 
  3.         PluginPackage pluginPackage) { 
  4.  
  5.         // Clear pools every time initEAR is called. See LEP-5452. 
  6.  
  7.         portletLocalService.clearCompanyPortletsPool(); 
  8.  
  9.         _portletAppsPool.clear(); 
  10.         _portletsPool.clear(); 
  11.         _portletIdsByStrutsPath.clear(); 
  12.         _friendlyURLMapperPortlets.clear(); 
  13.  
  14.         Map<String, Portlet> portletsPool = _getPortletsPool(); 
  15.  
  16.         try { 
  17.             Set<String> servletURLPatterns = _readWebXML(xmls[4]); 
  18.  
  19.             Set<String> portletIds = _readPortletXML( 
  20.                 servletContext, xmls[0], portletsPool, servletURLPatterns, 
  21.                 pluginPackage); 
  22.  
  23.             portletIds.addAll( 
  24.                 _readPortletXML( 
  25.                     servletContext, xmls[1], portletsPool, servletURLPatterns, 
  26.                     pluginPackage)); 
  27.  
  28.             Set<String> liferayPortletIds = 
  29.                 _readLiferayPortletXML(xmls[2], portletsPool); 
  30.  
  31.             liferayPortletIds.addAll( 
  32.                 _readLiferayPortletXML(xmls[3], portletsPool)); 
  33.  
  34.             // Check for missing entries in liferay-portlet.xml 
  35.  
  36.             for (String portletId : portletIds) { 
  37.                 if (_log.isWarnEnabled() && 
  38.                     !liferayPortletIds.contains(portletId)) { 
  39.  
  40.                     _log.warn( 
  41.                         "Portlet with the name " + portletId + 
  42.                             " is described in portlet.xml but does not " + 
  43.                                 "have a matching entry in liferay-portlet.xml"); 
  44.                 } 
  45.             } 
  46.  
  47.             // Check for missing entries in portlet.xml 
  48.  
  49.             for (String portletId : liferayPortletIds) { 
  50.                 if (_log.isWarnEnabled() && !portletIds.contains(portletId)) { 
  51.                     _log.warn( 
  52.                         "Portlet with the name " + portletId + 
  53.                             " is described in liferay-portlet.xml but does " + 
  54.                                 "not have a matching entry in portlet.xml"); 
  55.                 } 
  56.             } 
  57.  
  58.             // Remove portlets that should not be included 
  59.  
  60.             Iterator<Map.Entry<String, Portlet>> portletPoolsItr = 
  61.                 portletsPool.entrySet().iterator(); 
  62.  
  63.             while (portletPoolsItr.hasNext()) { 
  64.                 Map.Entry<String, Portlet> entry = portletPoolsItr.next(); 
  65.  
  66.                 Portlet portletModel = entry.getValue(); 
  67.  
  68.                 if (!portletModel.getPortletId().equals(PortletKeys.ADMIN) && 
  69.                     !portletModel.getPortletId().equals( 
  70.                         PortletKeys.MY_ACCOUNT) && 
  71.                     !portletModel.isInclude()) { 
  72.  
  73.                     portletPoolsItr.remove(); 
  74.  
  75.                     _friendlyURLMapperPortlets.remove( 
  76.                         portletModel.getPortletId()); 
  77.                 } 
  78.             } 
  79.  
  80.             // Sprite images 
  81.  
  82.             PortletApp portletApp = _getPortletApp(StringPool.BLANK); 
  83.  
  84.             _setSpriteImages(servletContext, portletApp, "/html/icons/"); 
  85.         } 
  86.         catch (Exception e) { 
  87.             _log.error(e, e); 
  88.         } 
  89.     } 

这里可以看出.它先去做一些清理工作(05-12行),然后它再去依次读取这些xml文件(所以,参数传递过来的xml文件的顺序不能错,17-32行),最终获取的是servletURLPattern的集合,portletId的集合,liferayPortletId的集合。然后检查portletId与liferayPortletId是否一一匹配(见第34-56行)。然后遍历Portlet池,吧PortletId=9(Admin Portlet),PortletId=2(My Account Portlet)和所有被标注为不应该include的Portlet从Portlet池和friendlyURLMapperPortlets中移除(见第58-78行),最后第80-87行,会sprite图片,它会在ROOT/html/icons/目录下递归的去找所有.png扩展名的文件,然后吧这些图片拼接成一张大图/html/icons/_sprite.png,然后把这些小图标在大图上的位置都写入/html/icons/_sprite.properties文件中。

 

封装每个Portlet到PortletBag中并且初始化这些Portlet:

  
  
  
  
  1. PortletBagFactory portletBagFactory = new PortletBagFactory(); 
  2.  
  3.         portletBagFactory.setClassLoader( 
  4.             PortalClassLoaderUtil.getClassLoader()); 
  5.         portletBagFactory.setServletContext(servletContext); 
  6.         portletBagFactory.setWARFile(false); 
  7.  
  8.         List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(); 
  9.  
  10.         for (int i = 0; i < portlets.size(); i++) { 
  11.             Portlet portlet = portlets.get(i); 
  12.  
  13.             portletBagFactory.create(portlet); 
  14.  
  15.             if (i == 0) { 
  16.                 initPortletApp(portlet, servletContext); 
  17.             } 
  18.         } 
  19.  
  20.         return portlets; 

从这段代码看,它会遍历上一步的得到的所有portlet(除了admin,my account,以及必须排除的portlet),然后把每一个Portlet放入PortletBag中。

 

其中第13行会调用portletBagFactory.create()方法:

它首先会指定这个Portlet的类加载器:

  
  
  
  
  1. if (!portletApp.isWARFile() && _warFile) { 
  2.         String contextPath = PortalUtil.getPathContext(); 
  3.  
  4.         _servletContext = ServletContextPool.get(contextPath); 
  5.  
  6.         _classLoader = PortalClassLoaderUtil.getClassLoader(); 
  7.     } 
  8.  
  9.     Class<?> portletClass = null
  10.  
  11.     try { 
  12.         portletClass = _classLoader.loadClass(portlet.getPortletClass()); 
  13.     } 
  14.     catch (Throwable e) { 
  15.     ... 

然后吧Portlet与整个Liferay的环境进行绑定,绑定信息填充到PortletBag中,绑定完之后,吧PortletBag添加到PortletPool中

  
  
  
  
  1. javax.portlet.Portlet portletInstance = 
  2.         (javax.portlet.Portlet)portletClass.newInstance(); 
  3.  
  4. ... 
  5.  
  6.     PortletBag portletBag = new PortletBagImpl( 
  7.         portlet.getPortletId(), _servletContext, portletInstance, 
  8.         configurationActionInstance, indexerInstances, openSearchInstance, 
  9.         friendlyURLMapperInstance, urlEncoderInstance, 
  10.         portletDataHandlerInstance, portletLayoutListenerInstance, 
  11.         pollerProcessorInstance, popMessageListenerInstance, 
  12.         socialActivityInterpreterInstance, socialRequestInterpreterInstance, 
  13.         webDAVStorageInstance, xmlRpcMethodInstance, 
  14.         controlPanelEntryInstance, assetRendererFactoryInstances, 
  15.         atomCollectionAdapterInstances, customAttributesDisplayInstances, 
  16.         permissionPropagatorInstance, workflowHandlerInstances, 
  17.         preferencesValidatorInstance, resourceBundles); 
  18.  
  19.     PortletBagPool.put(portlet.getRootPortletId(), portletBag); 

最后让PortletInstanceFactory吧这个Portlet实例创建出来并且关联到servleetContext:

  
  
  
  
  1. try { 
  2.             PortletInstanceFactoryUtil.create(portlet, _servletContext); 
  3.         } 


而第16行,则是为PortletApp做一些初始化工作,他们在MainServlet的initApp()方法中:

  
  
  
  
  1. protected void initPortletApp( 
  2.             Portlet portlet, ServletContext servletContext) 
  3.         throws PortletException { 
  4.  
  5.         PortletApp portletApp = portlet.getPortletApp(); 
  6.  
  7.         PortletConfig portletConfig = PortletConfigFactoryUtil.create( 
  8.             portlet, servletContext); 
  9.  
  10.         PortletContext portletContext = portletConfig.getPortletContext(); 
  11.  
  12.         Set<PortletFilter> portletFilters = portletApp.getPortletFilters(); 
  13.  
  14.         for (PortletFilter portletFilter : portletFilters) { 
  15.             PortletFilterFactory.create(portletFilter, portletContext); 
  16.         } 
  17.  
  18.         Set<PortletURLListener> portletURLListeners = 
  19.             portletApp.getPortletURLListeners(); 
  20.  
  21.         for (PortletURLListener portletURLListener : portletURLListeners) { 
  22.             PortletURLListenerFactory.create(portletURLListener); 
  23.         } 
  24.     } 

很显然,这里就是做一些Portlet环境配置工作,并且为Portlet添加一些监听器和过滤器。

 

现在,这些Portlet实例就都在Liferay服务器的内存中并且可用了。

你可能感兴趣的:(Liferay启动过程分析)