首页 > 解决方案 > 在不改变 server.xml 或 tomcat/web.xml 的情况下添加 tomcat 监听器 LifecycleListener

问题描述

我有以下代码,需要在 server.xml 中的以下条目,并且文件必须放在 tomcat/lib 中。

我想添加 tomcat 侦听器,不想对tomcat 服务器配置进行任何更改。有什么办法可以做到这一点?

注意:我已经尝试过“ServletContextListener”,但它作为 LifecycleListener 并不准确。

服务器.xml

<Listener className="com.tomcat.listener.TomcatListener"/>

Java 文件

package com.tomcat.listener;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;

public class TomcatListener implements LifecycleListener {
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if(Lifecycle.AFTER_START_EVENT.equals(event.getType())){
            System.out.print("Tomcat successfully started");
        }
    }
}

标签: javatomcat

解决方案


在 ServletContextListener、LifecycleListener 和反射的帮助下,我能够实现我所期望的。

所以在这里我们首先捕获 ServletContextListener 的事件以获取 ServletContext 然后使用反射,我们正在访问私有字段以在 Tomcat 的 ServletContext 实现中添加侦听器

CustomServletListener.java

import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationContextFacade;
import org.apache.catalina.core.StandardContext;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.lang.reflect.Field;

public final class CustomServletListener implements ServletContextListener{
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        
    }
    @Override
    public void contextInitialized(ServletContextEvent event) {
        addLifeCycleListener(event);
    }
    /**
     * Tomcat Implementation of ServletContext in ApplicationContextFacade, ApplicationContext,StandardContext as to addListener is located in StandardContext 
     * @param event
     */
    private void addLifeCycleListener(ServletContextEvent event){
        ApplicationContextFacade source = (ApplicationContextFacade) event.getSource();
        ApplicationContext objApplicationContext=get(source,"context");
        StandardContext objStandardContext = get(objApplicationContext,"context");
        objStandardContext.addLifecycleListener(new TomcatListener());
    }
    /**
     * Get class field using reflection as it is no way to direct access
     * @param object
     * @param fieldName
     * @param <V>
     * @return
     */
    @SuppressWarnings("unchecked")
    private <V> V get(Object object, String fieldName) {
        Class<?> clazz = object.getClass();
        Field field = null;
        boolean wasAccessable = false;
        while (clazz != null) {
            try {
                field = clazz.getDeclaredField(fieldName);
                wasAccessable = field.isAccessible();
                if(!wasAccessable){
                    field.setAccessible(true);
                }
                return (V) field.get(object);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(e);
            } finally {
                // Revert the Accessablility flag to previous state
                if(null!=field && field.isAccessible()!=wasAccessable){
                    field.setAccessible(wasAccessable); 
                }
            }
        }
        return null;
    }
}

TomcatListener.java

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;

public class TomcatListener implements LifecycleListener {
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if(Lifecycle.AFTER_START_EVENT.equals(event.getType())){
            System.out.print("Tomcat successfully started");
        }
    }
}

推荐阅读