Сплетение времени загрузки Tomcat 8 и AspectJ в приложении SpringBoot: не удалось загрузить InstrumentableClassLoader - PullRequest
0 голосов
/ 25 сентября 2019

Я пытаюсь настроить время загрузки AspectJ для встроенного Tomcat в приложении SpringBoot.Я следовал официальной документации Spring, но мои занятия не были сотканы.Кроме того, я вижу следующую трассировку стека:

2019-09-25 09:44:40.494  INFO [] 54907 --- [           main] o.a.c.loader.WebappClassLoaderBase       : Illegal access: this web application instance has been stopped already. Could not load [org.apache.tomcat.InstrumentableClassLoader]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.

java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.apache.tomcat.InstrumentableClassLoader]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1328)
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1316)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1175)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1136)
    at org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver.<init>(TomcatLoadTimeWeaver.java:69)
    at [my_package].Config.loadTimeWeaver(EventCoreConfig.java:33)
    at [my_package].Config$$EnhancerBySpringCGLIB$$12a75afc.CGLIB$loadTimeWeaver$0(<generated>)
    at [my_package].Config$$EnhancerBySpringCGLIB$$12a75afc$$FastClassBySpringCGLIB$$60dc0789.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
    at [my_package].config.Config$$EnhancerBySpringCGLIB$$12a75afc.loadTimeWeaver(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

Я полагаю, что это исключение является основной причиной проблемы переплетения.Вот мой файл конфигурации:

import org.apache.catalina.loader.WebappClassLoader;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableLoadTimeWeaving;
import org.springframework.context.annotation.Primary;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.aspectj.AnnotationTransactionAspect;

import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class Config {

    @Bean
    public LoadTimeWeaver loadTimeWeaver() {
        // this should enable load-time weaving in Tomcat
        return new TomcatLoadTimeWeaver(new WebappClassLoader());
    }

    @Bean
    @Primary
    public PlatformTransactionManager txManager(DataSource dataSource) {
        DataSourceTransactionManager txManager = new DataSourceTransactionManager(dataSource);
        AnnotationTransactionAspect aspect = new AnnotationTransactionAspect();
        aspect.setTransactionManager(txManager);
        return txManager;
    }
}

Любая помощь будет принята с благодарностью.

=============== ОБНОВЛЕНИЕ ================

В документации tomcat (https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/tomcat/InstrumentableClassLoader.html) есть предложение:

You should always program against the methods of this interface (whether using reflection or otherwise). The methods in WebappClassLoaderBase are protected by the default security manager if one is in use.

Не совсем уверенчто это значит и как обойти это ограничение.

Я перешел в режим отладки, и вот метод WebappClassLoaderBase, который вызывает упомянутое исключение:

    protected void checkStateForResourceLoading(String resource) throws IllegalStateException {
        // It is not permitted to load resources once the web application has
        // been stopped.
        if (!state.isAvailable()) {
            String msg = sm.getString("webappClassLoader.stopped", resource);
            IllegalStateException ise = new IllegalStateException(msg);
            log.info(msg, ise);
            throw ise;
        }
    }

state - это не STARTED, а NEW (isAvailable() возвращает false). До того, как эта строка из моего конфига будет выполнена: return new TomcatLoadTimeWeaver(new WebappClassLoader()); state было STARTED. Не понимаю, почему это идет к NEW.

Я думаю, что это связано с тем фактом, что я сам создаю экземпляр WebAppClassLoader в конфигурации. При этом SpringBoot имеет свою собственную версию загрузчика классов для tomcat: TomcatEmbeddedWebappClassLoader. Но как мне получить загрузчик классов SpringBoot, чтобы не создавать новый?

...