Agregue un filtro al paquete jar ejecutable de Spring Boot (sin intrusión de código)

Escenas

Cuando desarrollamos proyectos web basados ​​en el marco de arranque de primavera, en la mayoría de los casos, el proyecto se empaqueta como un paquete jar ejecutable y se comienza a usar java -jar project.jar (o no es demasiado problemático, a través de java -cp / - classpath) , este artículo también se refiere específicamente al método de inicio java -jar.

Si desea agregar un filtro web al proyecto, puede implementar directamente la clase javax.servlet.Filter para el desarrollo en el proyecto. No hay nada que decir.

Sin embargo, me encontré con un escenario en el que es necesario agregar un filtro a un paquete jar ejecutable empaquetado para realizar el procesamiento de permisos. No se permite desarrollar directamente en el código fuente y luego volver a empaquetarlo.

El escenario real es el siguiente: utilizamos nacos de código abierto como registro (versión 1.4.0 en ese momento). Pero los permisos de esta versión de nacos son realmente muy simples y no se ajustan a nuestro escenario Necesitamos hacer algunas extensiones adicionales. Pero el líder no quiere que modifique el código fuente directamente para empaquetar, porque después de que la comunidad lanza una nueva versión, si queremos actualizar simultáneamente, necesitamos volver a migrar el código y el paquete nuevamente.

Por lo tanto, quiero adoptar un método no intrusivo. Por supuesto, la primera idea puede ser adoptar un esquema de inserción de código y especificar un paquete jar de agente (-javaagent: agent.jar) al iniciar. Pero ah, si te encuentras en una situación como esta, realmente no recomiendo este método.Las razones se explicarán más adelante.

De hecho, originalmente quería usar bytebuddy para desarrollar un proxy jar modificando el bytecode. Cuando estaba listo para hacerlo, pensé en otra solución: usar la extensión SPI de Spring Boot.

solución

La idea principal es implementar la siguiente clase y luego dejar que Spring Boot configure y cargue automáticamente las clases relacionadas. Para esta clase, puede consultar directamente el documento relevante o buscar en Internet. Debería haber muchos artículos sobre instrucciones o uso. .

org.springframework.context.ApplicationContextInitializer

paso

1. Implemente la clase anterior y registre un ejemplo de filtro de la siguiente manera, donde DemoFilter es la clase de filtro empresarial que quiero agregar:

@Configuration
public class DemoFilterInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoFilterInitializer.class);

    public void initialize(ConfigurableApplicationContext applicationContext) {
        LOGGER.info("...initialize");
    }

    @Bean
    public FilterRegistrationBean<DemoFilter> registerLoginAuthFilterBean() {
        FilterRegistrationBean<DemoFilter> bean = new FilterRegistrationBean<DemoFilter>();
        bean.setFilter(new DemoFilter());
        bean.setName("DemoFilter");
        bean.addUrlPatterns("/*");
        bean.setOrder(1);
        return bean;
    }
}

2. Classpath: classpath: / resources / META-INF agrega un spring.factories, el contenido es el siguiente:

org.springframework.context.ApplicationContextInitializer=com.xuxd.DemoFilterInitializer

3. El proyecto está marcado como un paquete jar.

Respecto a los pasos anteriores, no hay mucho que decir, todos son paradigmas fijos. Además, no es el tema central de este artículo. Si está expuesto a conocimientos relevantes por primera vez, puede buscar información en Internet y obtener más información al respecto.

¿Dónde está este paquete de frasco de filtro?

Ubicación del paquete de la jarra del filtro

El proyecto de arranque de primavera ingresa directamente todas las dependencias en su directorio lib y se convierte en un paquete jar ejecutable.

Si busca en Internet, "java -jar comienza a especificar paquetes de dependencia externa", debería haber muchas respuestas, de hecho, solo hay unas pocas, pero no recomiendo usarlas, por ejemplo, la forma general de especificar la ruta de la extensión:

java -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:. -jar project.jar

Puede ver que hay un punto arriba, que es especificar el directorio actual, así que simplemente coloque el paquete jar de este filtro extendido en el directorio actual. Pero estas soluciones no son posibles, independientemente de dónde especifique el paquete jar o utilice otros métodos de configuración de parámetros de inicio. La razón es muy simple, todos deberían conocer el mecanismo de carga de clases de Java: el modelo de delegación padre, el problema radica aquí.

Lo primero que hay que tener claro es que algunos estudiantes pueden saberlo, mientras que otros no. La estructura del paquete jar producido por el proyecto spring boot es un poco diferente de nuestro jar normal. Todas sus dependencias se colocan en un directorio lib. Spring boot carga todas las dependencias y a través de un cargador de clases personalizado. Para clases relacionadas, si no No entiendo, puedes mirar el código fuente por ti mismo.

La carga delegada por el padre significa que cuando el cargador de clases actual carga una clase, primero deja que su cargador de clases padre la cargue. La relación de herencia padre-hijo del cargador: iniciar cargador de clases- "cargador de clases extendido-" cargador de clases del sistema (aplicación) -》 Cargador de clases personalizado. Este conocimiento es mucho y estoy interesado en verificar información relevante.

El problema ahora es que si la clase recién agregada especifica la ruta de clases de extensión, la carga el cargador de clases de extensión. Normalmente, esto no es un problema. El problema es que el filtro que escribimos no es una demostración en el negocio real. También tiene mucha lógica de código. También necesita depender de muchas bibliotecas de terceros. No solo la biblioteca incorporada de jdk es suficiente. Ese es el problema. Cuando empiezo, al cargar la clase de filtro, necesito cargar sus clases de terceros relacionadas. ¿Dónde están las clases de terceros relacionadas? En el directorio lib del paquete spring boot jar, es la clase personalizada cargador está cargado. Entonces no puede verlo. Cuando no puede encontrarlo, buscará. La parte superior es el cargador de clases de inicio. El cargador de clases de inicio tampoco se puede encontrar.

¿Qué debo hacer? Puedo pensar en poner todas las dependencias de todo el proyecto en la ruta de clase extendida. De todos modos, cuando se inicie la aplicación de arranque de primavera, se asignará a los padres para que la encuentren primero, y también se encontrará en la ruta extendida. classpath primero. No es necesario buscar en el directorio lib de Spring Boot, y también se han encontrado las clases en las que se basa este nuevo filtro. Todo el mundo lo ha encontrado, así que no hay problema.

Esta solución parece ser muy buena. Hice lo mismo al principio. Descomprimí el paquete jar de spring boot marcado con nacos, y luego puse todos los paquetes lib en la ruta de clase de extensión especificada. El resultado es esperado, pero la operación aún no se espera, porque la operación no parece normal, tal vez sepamos que está bien, pero cuando dejas operar a estudiantes que no conocen el conocimiento relevante, sospecharás mucho si el La operación afectará demasiado. Lo que es demasiado grande, espere, y es difícil de explicar. Y cuando estos dependen de mi servidor de carga, hay más de 80M, así que no puedo jugar así.

Más tarde, no pensé que fuera fácil de manejar, así que solo quería poner este paquete directamente en el directorio lib. La operación específica es usar el comando jar para descomprimir y descomprimir el paquete jar ejecutable de Spring Boot y ponerlo en el directorio lib. Archive de nuevo, si no tiene que preocuparse por las ventanas, abra win rar y péguelo directamente, y luego cargue el paquete jar en el servidor.

El comando es el siguiente:

Abrir la cremallera:

jar -xf nacos-server.jar

Luego, coloque el paquete jar del filtro y otros paquetes jar en el directorio BOOT-INF / lib que se descomprimió. 

Archive, pero no comprima el paquete jar importado (esta versión del cargador de clases personalizado de Spring Boot no admite la compresión), puede ser un poco más grande que el original:

jar -cfM0 nacos-server.jar ./

Por supuesto, la operación real será más complicada que esto, he proporcionado dos scripts, uno para agregar filtros y otro para restaurar. Entonces, en realidad, en el entorno del servidor, simplemente ejecute el script directamente (los anteriores son solo comandos relacionados con jar, y el script solo se proporciona de acuerdo con mi entorno, por lo que no se expandirá). La secuencia de comandos de recuperación es para hacer una copia de seguridad del paquete original cuando se agrega el filtro. Cuando se ejecuta la secuencia de comandos de recuperación, se restaura el contenedor original respaldado y se limpian otros datos. No descomprime el contenedor nuevamente, luego saca el filtro y luego comprimirlo.

¿Por qué no se recomienda utilizar un proxy?

El enfoque basado en proxy tiene un pequeño umbral técnico. Realmente, aunque ya existen buenos marcos de modificación de códigos de bytes, no es necesario que entiendas el código de bytes en profundidad, pero debes comprender estos marcos.

Más tarde, cuando tuve tiempo, también usé byte buddy para desarrollar este complemento para aumentar el filtro, y luego, cuando estaba probando, todavía encontré el problema de la carga de clases. Tomarse el tiempo para buscar información relevante no cumplió con mis expectativas (es decir, ejecutar directamente java -javaagent: demo.jar -jar procjet.jar, un paso está en su lugar). Hay relativamente pocos problemas relacionados y la solución no es con muchas ganas de usar. No hay otra forma que pasar el tiempo. Ve a ver el código fuente de skywalking, porque también usa bytebuddy. Si usa otros códigos de bytes para modificar el marco, digamos que debido a que las diferentes funciones tienen diferentes métodos de soporte y escritura, el código para resolver problemas puede ser diferente.

Supongo que te gusta

Origin blog.csdn.net/x763795151/article/details/114239142
Recomendado
Clasificación