gpt4 book ai didi

java - 在单独的 ClassLoader 中隔离模块后出现 Spring IllegalAccessException

转载 作者:太空宇宙 更新时间:2023-11-04 11:21:41 27 4
gpt4 key购买 nike

我遇到了涉及 jar clash between incompatible versions of BouncyCastle 的问题.

我们通过创建一个 bean 来解决这个问题,该 bean 使用 Spring 定义的 ClassLoader bean 作为属性注入(inject),从未存储在官方 WEB-INF/lib 文件夹中的类调用服务。

以下是 Bean 定义

<bean id="metainfJarClassloader" class="com.jdotsoft.jarloader.JarClassLoaderFactory" factory-method="create"/>
<bean id="jadesFactory" class="it.csttech.proxy.jades.JadesFactory">
<constructor-arg index="0" ref="metainfJarClassloader"/>
</bean>
<bean id="bouncyCastleBeanFactory" class="it.csttech.proxy.bouncyCastle.BouncyCastleBeanFactory">
<constructor-arg index="0" ref="metainfJarClassloader"/>
</bean>


<bean id="timestampService" class="it.csttech.pcp.services.spring.TimestampServiceImpl" lazy-init="true">
<property name="timestampServerConfig">
<bean factory-bean="jadesFactory" factory-method="createTSServerCfg">
-------------------
</bean>
</property>
<property name="jadesFactory" ref="jadesFactory" />
<property name="bouncyCastleBeanFactory" ref="bouncyCastleBeanFactory" />
<property name="jarClassLoader" ref="metainfJarClassloader" />
</bean>

这是如何运作的?经过认证的时间戳服务是在单独的 JAR 中定义的服务的包装器,并使用 metaInfClassLoader 通过反射进行实例化。 metaInfClassLoader 服务加载 META-INF/lib 下的 JAR 中包含的类

例如

WEB-INF
-- lib
-- timestamp.jar (expanded below)
-- META-INF
-- lib
-- it.infocert-jades-dts.jar
-- org.bouncycastle-bcprov.jar
-- src
-- it/csttech/pcp/services/spring
-- TimestampServiceImpl.java

TimestampServiceImpl 将从 META-INF 目录加载其依赖类。

我不明白的是,为什么在启用此组件并仅由延迟初始化的认证时间戳服务调用后,我在 Spring 中收到大量 IllegalAccessError

具体来说,我无法再访问 MVC Controller 中定义的任何私有(private)静态类

证据:

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.IllegalAccessError: it/package/NotificationsController$Dto
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:978) [spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) [spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) [spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) [servlet-api.jar:?]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [servlet-api.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) [catalina.jar:8.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:8.0.39]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.0.39]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) [catalina.jar:8.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:8.0.39]
at it.phoenix.web.context.PhoenixFilter.doFilter(PhoenixFilter.java:89) [phoenix-web-3.5.0.15.jar:17]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) [catalina.jar:8.0.39]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:8.0.39]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
------------
Caused by: java.lang.IllegalAccessError: it/package/NotificationController$Dto
at it.phoenix.web.controllers.secure.common.NotificationsController$$FastClassBySpringCGLIB$$7a88e7c5.invoke(<generated>) ~[?:?]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at it.phoenix.web.controllers.secure.common.NotificationsController$$EnhancerBySpringCGLIB$$5c5467a.scrollBottom(<generated>) ~[phoenix-web-3.5.0.15.jar:17]

问题的第 1 部分

IllegalAccessError 是什么意思?我总是在我的 MVC Controller 类中定义 DTO,将它们放入 private static 中,并且它始终有效

问题的第 2 部分

我看不到任何证据表明 JarClassLoader 实际上参与了加载 Controller 类。一旦发现任何 ClassLoader 类型的 bean,Spring 是否会替换主类加载器(或使用该类加载器增强自身)?

最佳答案

这不是 Spring 本身或我的代码的问题,而是JarClassLoader 的问题。本身就有问题。虽然有详细记录且易于理解,但以下行是罪魁祸首

    Thread.currentThread().setContextClassLoader(this); //loadClass method

分析

作者的分析是正确的,JarClassLoader一定是当前线程的主类加载器。从 jar 资源加载一个类后,该类可能会由于反射或仅仅因为它提供引用其他类的服务而加载其他类。那么谁递归地加载新类呢?当然是 JarClassLoader。

但是Spring出现了问题,我还是觉得不可思议。 Spring 不关心自定义类加载器 bean,但 ContextLoader class关心当前线程以创建线程和上下文之间的映射。可能是因为Spring想要隔离不同的上下文。荣誉!

最终调试 Spring 我发现了奇怪的情况。 Context map使用 JarClassLoader 而不是 Tomcat 的主要 URLClassLoader

解决方案

修改jdotsoft提供的JarClassLoader,以便实例化类后恢复原来的类加载器。如果依赖于类的类想要从线程而不是从 getClass()

使用 ClassLoader,这可能无法防止进一步的错误
    Thread.currentThread().setContextClassLoader(this);

成为

    ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this);

try {
---------
} finally {
Thread.currentThread().setContextClassLoader(old);
}

关于java - 在单独的 ClassLoader 中隔离模块后出现 Spring IllegalAccessException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44827534/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com