在MainServlet中,当初始化扩展环境之后,就开始处理全局启动事件,对应代码是:
- if (_log.isDebugEnabled()) {
- _log.debug("Process global startup events");
- }
- try {
- processGlobalStartupEvents();
- }
- ..
它会去调用processGlobalStartupEvents()方法:
- protected void processGlobalStartupEvents() throws Exception {
- EventsProcessorUtil.process(
- PropsKeys.GLOBAL_STARTUP_EVENTS, PropsValues.GLOBAL_STARTUP_EVENTS);
- }
我们看下系统是如何处理这些事件的,我们跟进到EventsProcessorUtil类的process方法,它实际传递了2个参数,第一个是字符串 "global.startup.events",第二个参数是字符串形式的事件类数组,它定义在portal.properties文件中:
- #
- # Global startup event that runs once when the portal initializes.
- #
- global.startup.events=com.liferay.portal.events.GlobalStartupAction
而实际处理的process方法在EventsProcessUtil类中,代码如下:
- public static void process(String key, String[] classes)
- throws ActionException {
- _instance.process(key, classes, null, null, null, null);
- }
最终消费它的方法是EventsProcessorUtil类的process()方法:
- public void process(
- String key, String[] classes, String[] ids,
- HttpServletRequest request, HttpServletResponse response,
- HttpSession session)
- throws ActionException {
- for (String className : classes) {
- if (Validator.isNull(className)) {
- return;
- }
- if (_log.isDebugEnabled()) {
- _log.debug("Process event " + className);
- }
- Object event = InstancePool.get(className);
- processEvent(event, ids, request, response, session);
- }
- if (Validator.isNull(key)) {
- return;
- }
- List<Object> events = _getEvents(key);
- for (Object event : events) {
- processEvent(event, ids, request, response, session);
- }
- }
所以,从第16跟进到InstancePool的_get()方法可以看出,它会去调用参数传递过来的事件类对应的类加载器,让其创建事件类的实例:
- private Object _get(String className, boolean logErrors) {
- className = className.trim();
- Object instance = _instances.get(className);
- if (instance == null) {
- ClassLoader portalClassLoader =
- PortalClassLoaderUtil.getClassLoader();
- try {
- Class<?> clazz = portalClassLoader.loadClass(className);
- instance = clazz.newInstance();
- _instances.put(className, instance);
- }
- ..
然后会吧这个事件类的实例传递进18行进行处理,我们继续跟进到EventProcessorImpl类的processEvent方法中:
- public void processEvent(
- Object event, String[] ids, HttpServletRequest request,
- HttpServletResponse response, HttpSession session)
- throws ActionException {
- if (event instanceof Action) {
- Action action = (Action)event;
- try {
- action.run(request, response);
- }
- ..
- }
- else if (event instanceof SessionAction) {
- SessionAction sessionAction = (SessionAction)event;
- try {
- sessionAction.run(session);
- }
- ..
- }
- else if (event instanceof SimpleAction) {
- SimpleAction simpleAction = (SimpleAction)event;
- simpleAction.run(ids);
- }
- }
可以发现,它只是判断事件类型,然后运行这个Action.
联系到实际,因为在portal.properties中,我们的事件类型是GlobalStartupAction,它继承自SimpleAction,所以,它运行上述代码的第22-26行,我们跟进到GlobalStartupAction的run方法,发现它做了许多事情:
事情1:插件(layout templates,portlets,themes)的自动部署
事件2:插件的热部署
....
我们这里只对自动部署详细展开说明。
它的代码如下:
- if (PrefsPropsUtil.getBoolean(
- PropsKeys.AUTO_DEPLOY_ENABLED,
- PropsValues.AUTO_DEPLOY_ENABLED)) {
- if (_log.isInfoEnabled()) {
- _log.info("Registering auto deploy directories");
- }
- File deployDir = new File(
- PrefsPropsUtil.getString(
- PropsKeys.AUTO_DEPLOY_DEPLOY_DIR,
- PropsValues.AUTO_DEPLOY_DEPLOY_DIR));
- File destDir = new File(DeployUtil.getAutoDeployDestDir());
- long interval = PrefsPropsUtil.getLong(
- PropsKeys.AUTO_DEPLOY_INTERVAL,
- PropsValues.AUTO_DEPLOY_INTERVAL);
- int blacklistThreshold = PrefsPropsUtil.getInteger(
- PropsKeys.AUTO_DEPLOY_BLACKLIST_THRESHOLD,
- PropsValues.AUTO_DEPLOY_BLACKLIST_THRESHOLD);
- List<AutoDeployListener> autoDeployListeners =
- getAutoDeployListeners();
- AutoDeployDir autoDeployDir = new AutoDeployDir(
- AutoDeployDir.DEFAULT_NAME, deployDir, destDir, interval,
- blacklistThreshold, autoDeployListeners);
- AutoDeployUtil.registerDir(autoDeployDir);
- }
- else {
- ..
不难发现,01-03行,它先去查看系统是否开启了自动部署配置,这个配置在portal.properties中,默认是开启的:
- #
- # Set this to true to enable auto deploy of layout templates, portlets, and
- # themes.
- #
- auto.deploy.enabled=true
然后它09-12行创建一个File对象指向自动部署目录,13行创建File对象指向部署的目标目录,14-16行获取自动部署的间隔时间,17-19行获取多少次失败就把被部署的插件拖到黑名单的临界值,这些值都可以从portal.properties中获取:
- #
- # Set the directory to scan for layout templates, portlets, and themes to
- # auto deploy.
- #
- auto.deploy.deploy.dir=${liferay.home}/deploy
- #
- # Set the directory where auto deployed WARs are copied to. The application
- # server or servlet container must know to listen on that directory.
- # Different containers have different hot deploy paths. For example, Tomcat
- # listens on "${catalina.base}/webapps" whereas JBoss listens on
- # "${jboss.home.dir}/deploy". Set a blank directory to automatically use the
- # application server specific directory.
- #
- auto.deploy.dest.dir=
- auto.deploy.default.dest.dir=../webapps
- auto.deploy.geronimo.dest.dir=${org.apache.geronimo.home.dir}/deploy
- auto.deploy.glassfish.dest.dir=${com.sun.aas.instanceRoot}/autodeploy
- auto.deploy.jboss.dest.dir=${jboss.home.dir}/standalone/deployments
- auto.deploy.jetty.dest.dir=${jetty.home}/webapps
- auto.deploy.jonas.dest.dir=${jonas.base}/deploy
- auto.deploy.resin.dest.dir=${resin.home}/webapps
- auto.deploy.tomcat.dest.dir=${catalina.base}/webapps
- auto.deploy.weblogic.dest.dir=${env.DOMAIN_HOME}/autodeploy
- #
- # Set the interval in milliseconds on how often to scan the directory for
- # changes.
- #
- auto.deploy.interval=3000
- #
- # Set the number of attempts to deploy a file before blacklisting it.
- #
- auto.deploy.blacklist.threshold=10
所以自动部署目录为${liferay_home}/deploy,部署到的位置,如果是tomcat服务器,则是${catalina.base}/webapps,扫描自动部署目录的间隔是3秒,尝试失败直到拉入黑名单的临界次数是10次(第9次失败就拉黑了)
然后第21-22行,获取自动部署监听器列表,这些监听器类都配置在portal.properties文件中:
- #
- # Input a list of comma delimited class names that implement
- # com.liferay.portal.kernel.deploy.auto.AutoDeployListener. These classes
- # are used to process the auto deployment of WARs.
- #
- auto.deploy.listeners=\
- com.liferay.portal.deploy.auto.OSGiAutoDeployListener,\
- com.liferay.portal.deploy.auto.ExtAutoDeployListener,\
- com.liferay.portal.deploy.auto.HookAutoDeployListener,\
- com.liferay.portal.deploy.auto.LayoutTemplateAutoDeployListener,\
- com.liferay.portal.deploy.auto.LiferayPackageAutoDeployListener,\
- com.liferay.portal.deploy.auto.PortletAutoDeployListener,\
- com.liferay.portal.deploy.auto.ThemeAutoDeployListener,\
- com.liferay.portal.deploy.auto.WebAutoDeployListener,\
- com.liferay.portal.deploy.auto.exploded.tomcat.HookExplodedTomcatListener,\
- com.liferay.portal.deploy.auto.exploded.tomcat.LayoutTemplateExplodedTomcatListener,\
- com.liferay.portal.deploy.auto.exploded.tomcat.PortletExplodedTomcatListener,\
- com.liferay.portal.license.deploy.auto.LicenseAutoDeployListener,com.liferay.portal.deploy.auto.exploded.tomcat.ThemeExplodedTomcatListener
然后第26-28行创建一个AutoDeployDir对象并吧所有的参数都填充进去,最后用工具类注册这个AutoDeployDir,注册的结果就是,用新的线程AutoDeployScanner去扫描自动部署目录,然后一旦发现部署目录有变化,则用相应的AutodeployListener来处理。