【问题标题】:how to setup load-time weaving with Spring and Tomcat WITHOUT using the -javaagent on the command line如何在不使用命令行上的 -javaagent 的情况下使用 Spring 和 Tomcat 设置加载时编织
【发布时间】:2016-06-29 20:47:17
【问题描述】:

我使用的是 Spring 3.2.9、Tomcat 6.0.44

当我的应用程序部署在 Tomcat 上时,我正在尝试配置我的应用程序的 Spring 检测提供程序(例如 spring-instrumentation.jar)以进行加载时编织。

我有一个不使用的要求: “-javaagent:/path/path/spring-instrument.jar”在命令行进行配置。

我了解到我可以通过修改应用程序的 Tomcat 配置(在 Tomcat 的 server.xml 或我的 Web 应用程序的 context.xml 中)的 元素来配置 Spring 工具。将适当的 元素添加到 server.xml 会导致我的应用程序被正确配置为与 Spring 的检测提供程序一起运行。将其添加到 context.xml(见下文)不会导致设置正常。

我有一个 META-INF/aop.xml 文件,如下所示:

    <aspectj>
        <weaver options="-verbose -showWeaveInfo -debug">
            <include within="com.mv.xx.services..*"/>
            <exclude within="com.mv.xx.aop..*"/>
        </weaver>
        <aspects>
            <aspect name="com.mv.xx.aop.MyAspect"/>
        </aspects>
    </aspectj>

我还通过将其添加到我的 Spring 上下文配置中来指定我想使用加载时编织:

 <context:load-time-weaver />

然后我将这个 jar 添加到我的应用程序的类路径中: spring-instrument-tomcat.jar

我已经尝试过:

在启动 Tomcat 时,如果我使用 -javaagent 参数在命令行中识别 spring-instrument.jar 的位置,如下所示:

-javaagent:/path/path2/spring-instrument-3.2.9.RELEASE.jar

一切正常。


接下来,我从命令行中删除了“-javaagent:/path/path2/spring-instrument-3.2.9.RELEASE.jar”。 在 Tomcat 的 server.xml 文件(位于 $CATALINE_HOME/conf)中,我向 元素添加了一个 元素,如下所示:

<Context path="/myApp" docBase="myApp">
    <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>

使用此配置,一切正常。但是我要求不要修改 Tomcat 的 server.xml,因为我无法控制 server.xml(DevOps 可以,并且不愿意修改它)。


接下来,我从 Tomcat 的 server.xml 中删除了 元素。 根据Spring docs,我可以在我的webapp中添加一个/META-INF/context.xml,并将之前在Tomcat的server.xml中的元素放到context.xml中,如下所示:

        <Context>
            <Context path="/myApp" docBase="myApp">
                <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
            </Context>
        </Context>

但是,当我重新启动 Tomcat 时,我在日志中收到一条错误消息:

    SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.weaving.AspectJWeavingEnabler#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar

在挖掘之后,我读到一些建议我修改 Spring 配置中的 &lt;context:load-time-weaver/&gt; 元素,如下所示:

        <context:load-time-weaver weaver-class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />

并将包含 InstrumentationLoadTimeWeaver.class 的 jar 添加到我的类路径中。

但是,当我这样做时,我会在日志中收到以下错误消息:

        SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
        java.lang.IllegalStateException: Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation.
    etc....

谁能解释如何在不使用命令行上的 -javaagent 和不修改 server.xml 的情况下使用 Spring 和 Tomcat 设置加载时编织?

【问题讨论】:

  • 同样的问题!有什么解决办法吗?

标签: spring tomcat spring-aop context.xml load-time-weaving


【解决方案1】:

这是我设法使用的代码,用于删除您提到的异常。 基本上你必须实现 LoadTimeWeavingConfigurer 并覆盖 getLoadTimeWeaver() 方法。

@Configuration
@ComponentScan(basePackages = "org.myproject")
@EnableAspectJAutoProxy
@EnableSpringConfigured
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.AUTODETECT)
public class Config implements LoadTimeWeavingConfigurer {

    @Override
    public LoadTimeWeaver getLoadTimeWeaver() {
        return new ReflectiveLoadTimeWeaver();
    }

    @Bean
    public InstrumentationLoadTimeWeaver loadTimeWeaver()  throws Throwable {
        InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
        return loadTimeWeaver;
    }

}

【讨论】:

  • @Ryan 我可能会在 xml 配置中实现相同的效果。看看 spring 文档 - docs.spring.io/spring/docs/current/javadoc-api/org/… 这可能会有所帮助。谢谢
  • 感谢您的链接。这看起来比我发现的更详细。我第一次尝试时它没有用,但很高兴听到它可能。
【解决方案2】:
https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving

从上面的链接尝试 maven 插件。它正在工作

【讨论】:

  • 虽然这在理论上可以回答这个问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。
【解决方案3】:

我使用invesdwin-instrument 来执行此操作。它允许您动态使用加载时间编织工具,这样您就不必使用任何 javaagent。

不过,我花了一些力气让它与 Tomcat 8.5 一起工作。但它最终可以在 Spring Boot 中使用此配置:

@SpringBootApplication
@EnableLoadTimeWeaving // instead of @ImportResource(locations = "classpath:/META-INF/ctx.spring.weaving.xml")
public class MySpringBootApplication {
    public static void main(final String[] args) {
        DynamicInstrumentationLoader.waitForInitialized(); //dynamically attach java agent to jvm if not already present
        DynamicInstrumentationLoader.initLoadTimeWeavingContext(); //weave all classes before they are loaded as beans
        SpringApplication.run(MySpringBootApplication.class, args); //start application, load some classes
    }
}

它也应该适用于以前版本的 Tomcat。

问候

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多