且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Liferay 启动过程分析12-处理全局启动事件

更新时间:2022-09-09 17:52:33

  在MainServlet中,当初始化扩展环境之后,就开始处理全局启动事件,对应代码是:


  1.     if (_log.isDebugEnabled()) { 
  2.             _log.debug("Process global startup events"); 
  3.         } 
  4.  
  5.         try { 
  6.             processGlobalStartupEvents(); 
  7.         } 
  8. .. 

 

它会去调用processGlobalStartupEvents()方法:


  1. protected void processGlobalStartupEvents() throws Exception { 
  2.         EventsProcessorUtil.process( 
  3.             PropsKeys.GLOBAL_STARTUP_EVENTS, PropsValues.GLOBAL_STARTUP_EVENTS); 
  4.     } 

 

我们看下系统是如何处理这些事件的,我们跟进到EventsProcessorUtil类的process方法,它实际传递了2个参数,第一个是字符串 "global.startup.events",第二个参数是字符串形式的事件类数组,它定义在portal.properties文件中:


  1.    # Global startup event that runs once when the portal initializes. 
  2.    # 
  3.    global.startup.events=com.liferay.portal.events.GlobalStartupAction 

 

而实际处理的process方法在EventsProcessUtil类中,代码如下:


  1. public static void process(String key, String[] classes) 
  2.         throws ActionException { 
  3.  
  4.         _instance.process(key, classes, nullnullnullnull); 
  5.     } 

 

最终消费它的方法是EventsProcessorUtil类的process()方法:


  1. public void process( 
  2.             String key, String[] classes, String[] ids, 
  3.             HttpServletRequest request, HttpServletResponse response, 
  4.             HttpSession session) 
  5.         throws ActionException { 
  6.  
  7.         for (String className : classes) { 
  8.             if (Validator.isNull(className)) { 
  9.                 return
  10.             } 
  11.  
  12.             if (_log.isDebugEnabled()) { 
  13.                 _log.debug("Process event " + className); 
  14.             } 
  15.  
  16.             Object event = InstancePool.get(className); 
  17.  
  18.             processEvent(event, ids, request, response, session); 
  19.         } 
  20.  
  21.         if (Validator.isNull(key)) { 
  22.             return
  23.         } 
  24.  
  25.         List<Object> events = _getEvents(key); 
  26.  
  27.         for (Object event : events) { 
  28.             processEvent(event, ids, request, response, session); 
  29.         } 
  30.     } 

 

所以,从第16跟进到InstancePool的_get()方法可以看出,它会去调用参数传递过来的事件类对应的类加载器,让其创建事件类的实例:


  1. private Object _get(String className, boolean logErrors) { 
  2.         className = className.trim(); 
  3.  
  4.         Object instance = _instances.get(className); 
  5.  
  6.         if (instance == null) { 
  7.             ClassLoader portalClassLoader = 
  8.                 PortalClassLoaderUtil.getClassLoader(); 
  9.  
  10.             try { 
  11.                 Class<?> clazz = portalClassLoader.loadClass(className); 
  12.  
  13.                 instance = clazz.newInstance(); 
  14.  
  15.                 _instances.put(className, instance); 
  16.             } 
  17. .. 

然后会吧这个事件类的实例传递进18行进行处理,我们继续跟进到EventProcessorImpl类的processEvent方法中:


  1. public void processEvent( 
  2.             Object event, String[] ids, HttpServletRequest request, 
  3.             HttpServletResponse response, HttpSession session) 
  4.         throws ActionException { 
  5.  
  6.         if (event instanceof Action) { 
  7.             Action action = (Action)event; 
  8.  
  9.             try { 
  10.                 action.run(request, response); 
  11.             } 
  12.            ..
  13.         } 
  14.         else if (event instanceof SessionAction) { 
  15.             SessionAction sessionAction = (SessionAction)event; 
  16.  
  17.             try { 
  18.                 sessionAction.run(session); 
  19.             } 
  20.             ..
  21.         } 
  22.         else if (event instanceof SimpleAction) { 
  23.             SimpleAction simpleAction = (SimpleAction)event; 
  24.  
  25.             simpleAction.run(ids); 
  26.         } 
  27.     } 

可以发现,它只是判断事件类型,然后运行这个Action.

 

联系到实际,因为在portal.properties中,我们的事件类型是GlobalStartupAction,它继承自SimpleAction,所以,它运行上述代码的第22-26行,我们跟进到GlobalStartupAction的run方法,发现它做了许多事情:

事情1:插件(layout templates,portlets,themes)的自动部署

事件2:插件的热部署

....

我们这里只对自动部署详细展开说明。

它的代码如下:


  1. if (PrefsPropsUtil.getBoolean( 
  2.                     PropsKeys.AUTO_DEPLOY_ENABLED, 
  3.                     PropsValues.AUTO_DEPLOY_ENABLED)) { 
  4.  
  5.                 if (_log.isInfoEnabled()) { 
  6.                     _log.info("Registering auto deploy directories"); 
  7.                 } 
  8.  
  9.                 File deployDir = new File( 
  10.                     PrefsPropsUtil.getString( 
  11.                         PropsKeys.AUTO_DEPLOY_DEPLOY_DIR, 
  12.                         PropsValues.AUTO_DEPLOY_DEPLOY_DIR)); 
  13.                 File destDir = new File(DeployUtil.getAutoDeployDestDir()); 
  14.                 long interval = PrefsPropsUtil.getLong( 
  15.                     PropsKeys.AUTO_DEPLOY_INTERVAL, 
  16.                     PropsValues.AUTO_DEPLOY_INTERVAL); 
  17.                 int blacklistThreshold = PrefsPropsUtil.getInteger( 
  18.                     PropsKeys.AUTO_DEPLOY_BLACKLIST_THRESHOLD, 
  19.                     PropsValues.AUTO_DEPLOY_BLACKLIST_THRESHOLD); 
  20.  
  21.                 List<AutoDeployListener> autoDeployListeners = 
  22.                     getAutoDeployListeners(); 
  23.  
  24.                 AutoDeployDir autoDeployDir = new AutoDeployDir( 
  25.                     AutoDeployDir.DEFAULT_NAME, deployDir, destDir, interval, 
  26.                     blacklistThreshold, autoDeployListeners); 
  27.  
  28.                 AutoDeployUtil.registerDir(autoDeployDir); 
  29.             } 
  30.             else { 
  31.             .. 

不难发现,01-03行,它先去查看系统是否开启了自动部署配置,这个配置在portal.properties中,默认是开启的:


  1.    # Set this to true to enable auto deploy of layout templates, portlets, and 
  2.    # themes. 
  3.    # 
  4.    auto.deploy.enabled=true 

然后它09-12行创建一个File对象指向自动部署目录,13行创建File对象指向部署的目标目录,14-16行获取自动部署的间隔时间,17-19行获取多少次失败就把被部署的插件拖到黑名单的临界值,这些值都可以从portal.properties中获取:


  1.   # Set the directory to scan for layout templates, portlets, and themes to 
  2.   # auto deploy. 
  3.   # 
  4.   auto.deploy.deploy.dir=${liferay.home}/deploy 
  5.  
  6.   # 
  7.   # Set the directory where auto deployed WARs are copied to. The application 
  8.   # server or servlet container must know to listen on that directory. 
  9.   # Different containers have different hot deploy paths. For example, Tomcat 
  10.   # listens on "${catalina.base}/webapps" whereas JBoss listens on 
  11.   # "${jboss.home.dir}/deploy"Set a blank directory to automatically use the 
  12.   # application server specific directory. 
  13.   # 
  14.   auto.deploy.dest.dir= 
  15.   auto.deploy.default.dest.dir=../webapps 
  16.   auto.deploy.geronimo.dest.dir=${org.apache.geronimo.home.dir}/deploy 
  17.   auto.deploy.glassfish.dest.dir=${com.sun.aas.instanceRoot}/autodeploy 
  18.   auto.deploy.jboss.dest.dir=${jboss.home.dir}/standalone/deployments 
  19.   auto.deploy.jetty.dest.dir=${jetty.home}/webapps 
  20.   auto.deploy.jonas.dest.dir=${jonas.base}/deploy 
  21.   auto.deploy.resin.dest.dir=${resin.home}/webapps 
  22.   auto.deploy.tomcat.dest.dir=${catalina.base}/webapps 
  23.   auto.deploy.weblogic.dest.dir=${env.DOMAIN_HOME}/autodeploy 
  24.  
  25.   # 
  26.   # Set the interval in milliseconds on how often to scan the directory for 
  27.   # changes. 
  28.   # 
  29.   auto.deploy.interval=3000 
  30.  
  31.   # 
  32.   # Set the number of attempts to deploy a file before blacklisting it. 
  33.   # 
  34.   auto.deploy.blacklist.threshold=10 

所以自动部署目录为${liferay_home}/deploy,部署到的位置,如果是tomcat服务器,则是${catalina.base}/webapps,扫描自动部署目录的间隔是3秒,尝试失败直到拉入黑名单的临界次数是10次(第9次失败就拉黑了)

 

然后第21-22行,获取自动部署监听器列表,这些监听器类都配置在portal.properties文件中:


  1.    # Input a list of comma delimited class names that implement 
  2.    # com.liferay.portal.kernel.deploy.auto.AutoDeployListener. These classes 
  3.    # are used to process the auto deployment of WARs. 
  4.    # 
  5.    auto.deploy.listeners=\ 
  6.        com.liferay.portal.deploy.auto.OSGiAutoDeployListener,\ 
  7.        com.liferay.portal.deploy.auto.ExtAutoDeployListener,\ 
  8.        com.liferay.portal.deploy.auto.HookAutoDeployListener,\ 
  9.        com.liferay.portal.deploy.auto.LayoutTemplateAutoDeployListener,\ 
  10.        com.liferay.portal.deploy.auto.LiferayPackageAutoDeployListener,\ 
  11.        com.liferay.portal.deploy.auto.PortletAutoDeployListener,\ 
  12.        com.liferay.portal.deploy.auto.ThemeAutoDeployListener,\ 
  13.        com.liferay.portal.deploy.auto.WebAutoDeployListener,\ 
  14.        com.liferay.portal.deploy.auto.exploded.tomcat.HookExplodedTomcatListener,\ 
  15.        com.liferay.portal.deploy.auto.exploded.tomcat.LayoutTemplateExplodedTomcatListener,\ 
  16.        com.liferay.portal.deploy.auto.exploded.tomcat.PortletExplodedTomcatListener,\ 
  17.       com.liferay.portal.license.deploy.auto.LicenseAutoDeployListener,com.liferay.portal.deploy.auto.exploded.tomcat.ThemeExplodedTomcatListener 

 

然后第26-28行创建一个AutoDeployDir对象并吧所有的参数都填充进去,最后用工具类注册这个AutoDeployDir,注册的结果就是,用新的线程AutoDeployScanner去扫描自动部署目录,然后一旦发现部署目录有变化,则用相应的AutodeployListener来处理。





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