乐虎游戏|乐虎国际登录|欢迎你

Liferay 运营进度深入分析6-初叶化Portlets

日期:2019-11-07编辑作者:计算机资讯

在MainServlet中,初始化Portlets之后,就开始初始化布局模板了,对应代码是:

Spring源码学习笔记(二)

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

if (_log.isDebugEnabled()) {             _log.debug("Initialize layout templates");         }          try {             initLayoutTemplates(pluginPackage, portlets);         } .. 

  前言----

对应的代码是:

 

       最近花了些时间看了《Spring源码深度解析》这本书,算是入门了Spring的源码吧。打算写下系列文章,回忆一下书的内容,总结代码的运行流程。推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的《Spring源码深度解析》这本书,会是个很好的入门。

if (_log.isDebugEnabled()) {             _log.debug("Initialize portlets");         }          List<Portlet> portlets = null;          try {             portlets = initPortlets(pluginPackage);         } ... 

它会调用initLayoutTemplates方法:


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

protected void initLayoutTemplates(             PluginPackage pluginPackage, List<Portlet> portlets)         throws Exception {          ServletContext servletContext = getServletContext();          String[] xmls = new String[] {             HttpUtil.URLtoString(                 servletContext.getResource(                     "/WEB-INF/liferay-layout-templates.xml")),             HttpUtil.URLtoString(                 servletContext.getResource(                     "/WEB-INF/liferay-layout-templates-ext.xml"))         };          LayoutTemplateLocalServiceUtil.init(             servletContext, xmls, pluginPackage);     } 

 

读取配置文件:

首先,第05行取得servlet上下文,然后第07-14行去ROOT下的/WEB-INF中去找2个XML配置文件,我看了下Liferay CE版本下的liferay-layout-template.xml,发现这里定义了2套模板,一套是<standard>,一套是<custom>,,每套下又细分为各种小模板,每种模板都用tpl文件来定义。

    SpringMVC 的的入口就是 DispatcherServlet , 也是主要逻辑实现的地方。  先看看 DispatcherServlet 的 继承关系。

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

 

计算机,    计算机 1

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"))         }; .... 

然后在第16行,调用LayoutTemplateLocalServiceUtil.init方法来读取这些xml配置文件,并且进行初始化这些模板:

    可以看出 DispatcherServlet 也应该有和普通 Servlet 同样的逻辑方法, 即 doDelete(), doGet(), doPost(), doPut() 以及 init(), destory() 等方法。

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

public static java.util.List<com.liferay.portal.kernel.util.ObjectValuePair<java.lang.String, java.lang.Boolean>> init(     java.lang.String servletContextName,     javax.servlet.ServletContext servletContext, java.lang.String[] xmls,     com.liferay.portal.kernel.plugin.PluginPackage pluginPackage) {     return getService()                .init(servletContextName, servletContext, xmls, pluginPackage); } 

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

 

DispatcherServlet的初始化

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

它最终会调用LayoutTemplateLocalServiceImpl类的init()方法:

   初始化是调用 Servlet 的 init() 方法。

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

public List<ObjectValuePair<String, Boolean>> init(         String servletContextName, ServletContext servletContext, String[] xmls,         PluginPackage pluginPackage) {          List<ObjectValuePair<String, Boolean>> layoutTemplateIds =             new ArrayList<ObjectValuePair<String, Boolean>>();          try {             for (int i = 0; i < xmls.length; i++) {                 Set<ObjectValuePair<String, Boolean>> curLayoutTemplateIds =                     _readLayoutTemplates(                         servletContextName, servletContext, xmls[i],                         pluginPackage);                  Iterator<ObjectValuePair<String, Boolean>> itr =                     curLayoutTemplateIds.iterator();                  while (itr.hasNext()) {                     ObjectValuePair<String, Boolean> ovp = itr.next();                      if (!layoutTemplateIds.contains(ovp)) {                         layoutTemplateIds.add(ovp);                     }                 }             }         }         catch (Exception e) {             _log.error(e, e);         }          return layoutTemplateIds;     } 
    public final void init() throws ServletException {

        try {
            // 第一步: init-param的封装
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
            //第二步: 封装为 BeanWrapper 类,Spring可以把 获取的 init-param 属性注入
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            //第三步: 针对 Resource 属性 注册属性编辑器
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            //第四步: 添加属性
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            throw var4;
        }
        // 第五步: 子类扩展
        this.initServletBean();

    }

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

计算机 2

    在 init() 方法 第一步中, 封装 初始化 参数, 找到一个内部类, 逻辑放在了构造函数中, 一段简单清晰的代码, 来一波!!! d=====( ̄▽ ̄*)b 

 

    private static class ServletConfigPropertyValues extends MutablePropertyValues {
        public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties) throws ServletException {
            // 第一步:  根据需要的属性, 生成迭代器, 并填充
            Set<String> missingProps = requiredProperties != null && !requiredProperties.isEmpty()?new HashSet(requiredProperties):null;
            Enumeration en = config.getInitParameterNames();

            while(en.hasMoreElements()) {
                String property = (String)en.nextElement();
                Object value = config.getInitParameter(property);
                this.addPropertyValue(new PropertyValue(property, value));
                //第二步:  填充的属性要移出集合
                if(missingProps != null) {
                    missingProps.remove(property);
                }
            }
            //第三步: 遍历完后还有未填充属性, 需要抛异常  
            if(missingProps != null && missingProps.size() > 0) {
                throw new ServletException("Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", "));
            }
        }
    }

初始化EAR:

    在 init()方法 第四步中, 注入的属性包括 contextAttribute, contextClass, nameSpace, contextConfigLocation 等属性, 

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

    在 init()方法 第五步中, 父类 FrameworkServlet 定义了 initServletBean() 方法。 初始化了 ServletBean 。

PortletLocalServiceUtil.initEAR(servletContext, xmls, pluginPackage); 
    protected final void initServletBean() throws ServletException {

        long startTime = System.currentTimeMillis();

        try {
            //第一步:  去掉日志, 忽略时间,剩下这句
            this.webApplicationContext = this.initWebApplicationContext();
            this.initFrameworkServlet();
        }

        if(this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
        }

    }

它最终会调用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 images              PortletApp portletApp = _getPortletApp(StringPool.BLANK);              _setSpriteImages(servletContext, portletApp, "/html/icons/");         }         catch (Exception e) {             _log.error(e, e);         }     } 

计算机 3

 

    

    在 initServletBean() 方法中, 只有 创建或刷新 WebApplicationContext 实例的方法。

 1     protected WebApplicationContext initWebApplicationContext() {
 2         //第一步:  获取context实例
 3         WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
 4         WebApplicationContext wac = null;
 5         if(this.webApplicationContext != null) {
 6             //第二步:  判断已在构造函数中注入
 7             wac = this.webApplicationContext;
 8             if(wac instanceof ConfigurableWebApplicationContext) {
 9                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
10                 if(!cwac.isActive()) {
11                     if(cwac.getParent() == null) {
12                         cwac.setParent(rootContext);
13                     }
14 
15                     //第三步:  刷新上下文  
16                     this.configureAndRefreshWebApplicationContext(cwac);
17                 }
18             }
19         }
20         //第四步:  根据contextAttribute 属性创建 context
21         if(wac == null) {
22             wac = this.findWebApplicationContext();
23         }
24         //第五步:  还是TMD 的木有, 重新创建一个
25         if(wac == null) {
26             wac = this.createWebApplicationContext(rootContext);
27         }
28         //第六步:  context不是一个支持刷新的ConfigurableWebApplicationContext 或 构造函数注入的context已经被刷新
29         if(!this.refreshEventReceived) {
30             this.onRefresh(wac);
31         }
32         //第七步:  把context 实例 设置为 contextAttributes的属性
33         if(this.publishContext) {
34             String attrName = this.getServletContextAttributeName();
35             this.getServletContext().setAttribute(attrName, wac);
36             if(this.logger.isDebugEnabled()) {
37                 this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
38             }
39         }
40 
41         return wac;
42     }

    在 initWebApplicationContext() 方法中, 第四步通过 contextAttribute 查找 context, 其中 contextAttribute 属性在 web.xml 文件中配置,  默认为

WebApplicationContext.class.getName() + ".ROOT'。 

    protected WebApplicationContext findWebApplicationContext() {
        //第一步: 获取属性
        String attrName = this.getContextAttribute();
        if(attrName == null) {
            return null;
        } else {
            //第二步:  根据属性获取 context
            WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext(), attrName);
            if(wac == null) {
                throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
            } else {
                return wac;
            }
        }
    } 

    在 *initWebApplicationContext() 方法中, 若 判断 context 始终为null, 则 通过 **createWebApplicationContext()*** 方法创建新的 context 实例。

1     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
2         //往下调用方法
3         return this.createWebApplicationContext((ApplicationContext)parent);
4     }

 1     protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
 2         Class<?> contextClass = this.getContextClass();
 3         if(this.logger.isDebugEnabled()) {
 4             this.logger.debug("Servlet with name '" + this.getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]");
 5         }
 6 
 7         //第一步: 类型判断        
 8      if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
 9             throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
10         } else {
11             //第二步:  反射创建 context
12             ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
13             //第三步:  为 context 设置属性
14             wac.setEnvironment(this.getEnvironment());
15             //第四步: parent 为在ContextLoaderListener初始化时的 WebApplicationContext 实例
16             wac.setParent(parent);
17             wac.setConfigLocation(this.getContextConfigLocation());
18             this.configureAndRefreshWebApplicationContext(wac);
19             return wac;
20         }
21     }

    在 *initWebApplicationContext() 方法第三步中, 无论通过构造函数 还是 重新创建, 都会调用  **this.configureAndRefreshWebApplicationContext(wac) *** 方法。 虽然看起来像给子类扩展的, 但是实际上 代码不可貌相啊。   ----------------(^o^)/!!!

本文由乐虎游戏发布于计算机资讯,转载请注明出处:Liferay 运营进度深入分析6-初叶化Portlets

关键词:

文件操作,c++文件操作

文件操作,c++文件操作 Java文件操作 读写操作,java文件操作读写 一、Java读取文件 案例1:读取D盘的1.txt文件      ...

详细>>

[.NET] 《Effective C#》快速笔记(三)- 使用 C# 表达设计,

[.NET] 《Effective C#》飞快笔记(三卡塔尔国- 使用 C# 表达设计, 《Effective C#》急忙笔记(三卡塔 尔(阿拉伯语:قطر...

详细>>

C#之事件

C#之事件, 事件基于委托,可以为任何大器晚成种委托项目提供生龙活虎种宣布订阅机制。 使用event关键字将多少个...

详细>>

Hadoop namenode配置以及问题处理

先是步:修改core-site.xml,配置如下内容: 尝试情形 重装系统后有折腾了漫长,才解决。。感到依然不可信赖。。先...

详细>>