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服务器的内存中并且可用了。





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/906469,如需转载请自行联系原作者

目录
相关文章
|
jvm-sandbox Shell Java
Jvm-Sandbox源码分析--启动时加载模块
在上一篇Jvm-Sandbox源码分析--启动简析 简单介绍了一下jvm-sandbox启动流程,在这篇文章中我们来分析一下系统模块和用户的自定义模块在启动时,是怎么加载的。
4433 0