在MainServlet中,初始化插件包之后,就开始初始化Portlets:
对应的代码是:
- if (_log.isDebugEnabled()) {
- _log.debug("Initialize portlets");
- }
- List<Portlet> portlets = null;
- try {
- portlets = initPortlets(pluginPackage);
- }
- ...
它会去调用initPortlets方法,并且传入一个我们上一步刚初始化的核心pluginPackage,我们来细看它究竟做了哪些事情:
读取配置文件:
首先,它去取得servletContext,然后获取一组xml配置文件:
- protected List<Portlet> initPortlets(PluginPackage pluginPackage)
- throws Exception {
- ServletContext servletContext = getServletContext();
- String[] xmls = new String[] {
- HttpUtil.URLtoString(
- servletContext.getResource(
- "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
- HttpUtil.URLtoString(
- servletContext.getResource("/WEB-INF/portlet-ext.xml")),
- HttpUtil.URLtoString(
- servletContext.getResource("/WEB-INF/liferay-portlet.xml")),
- HttpUtil.URLtoString(
- servletContext.getResource("/WEB-INF/liferay-portlet-ext.xml")),
- HttpUtil.URLtoString(
- servletContext.getResource("/WEB-INF/web.xml"))
- };
- ....
这些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:
然后,调用以下代码来初始化:
- PortletLocalServiceUtil.initEAR(servletContext, xmls, pluginPackage);
它最终会调用PortletLocalServiceImpl的initEAR方法:
- public void initEAR(
- ServletContext servletContext, String[] xmls,
- PluginPackage pluginPackage) {
- // Clear pools every time initEAR is called. See LEP-5452.
- portletLocalService.clearCompanyPortletsPool();
- _portletAppsPool.clear();
- _portletsPool.clear();
- _portletIdsByStrutsPath.clear();
- _friendlyURLMapperPortlets.clear();
- Map<String, Portlet> portletsPool = _getPortletsPool();
- try {
- Set<String> servletURLPatterns = _readWebXML(xmls[4]);
- Set<String> portletIds = _readPortletXML(
- servletContext, xmls[0], portletsPool, servletURLPatterns,
- pluginPackage);
- portletIds.addAll(
- _readPortletXML(
- servletContext, xmls[1], portletsPool, servletURLPatterns,
- pluginPackage));
- Set<String> liferayPortletIds =
- _readLiferayPortletXML(xmls[2], portletsPool);
- liferayPortletIds.addAll(
- _readLiferayPortletXML(xmls[3], portletsPool));
- // Check for missing entries in liferay-portlet.xml
- for (String portletId : portletIds) {
- if (_log.isWarnEnabled() &&
- !liferayPortletIds.contains(portletId)) {
- _log.warn(
- "Portlet with the name " + portletId +
- " is described in portlet.xml but does not " +
- "have a matching entry in liferay-portlet.xml");
- }
- }
- // Check for missing entries in portlet.xml
- for (String portletId : liferayPortletIds) {
- if (_log.isWarnEnabled() && !portletIds.contains(portletId)) {
- _log.warn(
- "Portlet with the name " + portletId +
- " is described in liferay-portlet.xml but does " +
- "not have a matching entry in portlet.xml");
- }
- }
- // Remove portlets that should not be included
- Iterator<Map.Entry<String, Portlet>> portletPoolsItr =
- portletsPool.entrySet().iterator();
- while (portletPoolsItr.hasNext()) {
- Map.Entry<String, Portlet> entry = portletPoolsItr.next();
- Portlet portletModel = entry.getValue();
- if (!portletModel.getPortletId().equals(PortletKeys.ADMIN) &&
- !portletModel.getPortletId().equals(
- PortletKeys.MY_ACCOUNT) &&
- !portletModel.isInclude()) {
- portletPoolsItr.remove();
- _friendlyURLMapperPortlets.remove(
- portletModel.getPortletId());
- }
- }
- // Sprite p_w_picpaths
- PortletApp portletApp = _getPortletApp(StringPool.BLANK);
- _setSpriteImages(servletContext, portletApp, "/html/icons/");
- }
- catch (Exception e) {
- _log.error(e, e);
- }
- }
这里可以看出.它先去做一些清理工作(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:
- PortletBagFactory portletBagFactory = new PortletBagFactory();
- portletBagFactory.setClassLoader(
- PortalClassLoaderUtil.getClassLoader());
- portletBagFactory.setServletContext(servletContext);
- portletBagFactory.setWARFile(false);
- List<Portlet> portlets = PortletLocalServiceUtil.getPortlets();
- for (int i = 0; i < portlets.size(); i++) {
- Portlet portlet = portlets.get(i);
- portletBagFactory.create(portlet);
- if (i == 0) {
- initPortletApp(portlet, servletContext);
- }
- }
- return portlets;
从这段代码看,它会遍历上一步的得到的所有portlet(除了admin,my account,以及必须排除的portlet),然后把每一个Portlet放入PortletBag中。
其中第13行会调用portletBagFactory.create()方法:
它首先会指定这个Portlet的类加载器:
- if (!portletApp.isWARFile() && _warFile) {
- String contextPath = PortalUtil.getPathContext();
- _servletContext = ServletContextPool.get(contextPath);
- _classLoader = PortalClassLoaderUtil.getClassLoader();
- }
- Class<?> portletClass = null;
- try {
- portletClass = _classLoader.loadClass(portlet.getPortletClass());
- }
- catch (Throwable e) {
- ...
然后吧Portlet与整个Liferay的环境进行绑定,绑定信息填充到PortletBag中,绑定完之后,吧PortletBag添加到PortletPool中
- javax.portlet.Portlet portletInstance =
- (javax.portlet.Portlet)portletClass.newInstance();
- ...
- PortletBag portletBag = new PortletBagImpl(
- portlet.getPortletId(), _servletContext, portletInstance,
- configurationActionInstance, indexerInstances, openSearchInstance,
- friendlyURLMapperInstance, urlEncoderInstance,
- portletDataHandlerInstance, portletLayoutListenerInstance,
- pollerProcessorInstance, popMessageListenerInstance,
- socialActivityInterpreterInstance, socialRequestInterpreterInstance,
- webDAVStorageInstance, xmlRpcMethodInstance,
- controlPanelEntryInstance, assetRendererFactoryInstances,
- atomCollectionAdapterInstances, customAttributesDisplayInstances,
- permissionPropagatorInstance, workflowHandlerInstances,
- preferencesValidatorInstance, resourceBundles);
- PortletBagPool.put(portlet.getRootPortletId(), portletBag);
最后让PortletInstanceFactory吧这个Portlet实例创建出来并且关联到servleetContext:
- try {
- PortletInstanceFactoryUtil.create(portlet, _servletContext);
- }
而第16行,则是为PortletApp做一些初始化工作,他们在MainServlet的initApp()方法中:
- protected void initPortletApp(
- Portlet portlet, ServletContext servletContext)
- throws PortletException {
- PortletApp portletApp = portlet.getPortletApp();
- PortletConfig portletConfig = PortletConfigFactoryUtil.create(
- portlet, servletContext);
- PortletContext portletContext = portletConfig.getPortletContext();
- Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
- for (PortletFilter portletFilter : portletFilters) {
- PortletFilterFactory.create(portletFilter, portletContext);
- }
- Set<PortletURLListener> portletURLListeners =
- portletApp.getPortletURLListeners();
- for (PortletURLListener portletURLListener : portletURLListeners) {
- PortletURLListenerFactory.create(portletURLListener);
- }
- }
很显然,这里就是做一些Portlet环境配置工作,并且为Portlet添加一些监听器和过滤器。
现在,这些Portlet实例就都在Liferay服务器的内存中并且可用了。