AspectJ:尝试使用外部aop.xml文件时出现ClassLoading问题 [英] AspectJ: ClassLoading issue when trying to use external aop.xml file

查看:144
本文介绍了AspectJ:尝试使用外部aop.xml文件时出现ClassLoading问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试外化aop.xml的配置,所以我从 META-INF aop.xml >并使其在服务器中可供sys管理员手动配置。

I m trying to externalize the configuration of aop.xml so I removed the aop.xml from META-INF and made it available in the server for manual configuration by sys admins.

当我尝试使用外部aop.xml时使用

When I try to use an external aop.xml using

-Dorg.aspectj.weaver.loadtime.configuration="file:D:\Workspace\tomcat7\shared\lib\aop.xml"

我得到 java.lang.RuntimeException:无法注册非方面:aspectclass .. .. 主要是因为当时还没有 AppClassLoader 加载aj casses。并且下次它尝试从 WebAppClassLoader 注册方面时(在加载所有类之后),它工作正常,但我仍然得到第一次尝试记录的异常注册它。

I get java.lang.RuntimeException: Cannot register non aspect: aspectclass.... mainly because the aj casses are not loaded by AppClassLoader yet at that time. And the next time it tries to register the aspects from the WebAppClassLoader ( after all the classes are loaded), it works fine, but i still get the exceptions logged from the 1st attempt to register it.

该异常被捕获并记录在 ClassLoaderWeavingAdaptor.java 第307行。

The exception is caught and logged at ClassLoaderWeavingAdaptor.java line 307.

当调用以下行时:
success = registerAspects(weaver,loader,definitions);

when the following line is called: success = registerAspects(weaver, loader, definitions);

异常是捕获并记录。

    try {
        registerOptions(weaver, loader, definitions);
        registerAspectExclude(weaver, loader, definitions);
        registerAspectInclude(weaver, loader, definitions);
        success = registerAspects(weaver, loader, definitions);
        registerIncludeExclude(weaver, loader, definitions);
        registerDump(weaver, loader, definitions);
    } catch (Exception ex) {
        trace.error("register definition failed", ex);
        success = false;
        warn("register definition failed", (ex instanceof AbortException) ? null : ex);
    }

异常在BcelWeaver.java中的以下行中被精确抛出

the exception is thrown excactly in the following line in BcelWeaver.java

if (type.isAspect()) {
      ......
} else {
        // FIXME AV - better warning upon no such aspect from aop.xml
        RuntimeException ex = new RuntimeException("Cannot register non aspect: " + type.getName() + " , " + aspectName);
        if (trace.isTraceEnabled()) {
            trace.exit("addLibraryAspect", ex);
        }
        throw ex;
    }

如何防止classLoader将错误记录到控制台方面尚未加载。我正在考虑注释从源文件记录异常并重建aspectjweaver jar文件的行,但是在没有修改aspectj源的情况下寻找更好的解决方案。

How can I prevent the classLoader from logging the error to the console, when the aspects are not loaded yet. I was thinking of commenting the line that logs the exception from the source file and rebuilding the aspectjweaver jar file, but was looking for a better solution without modifying the aspectj source.

推荐答案

我不确定你的问题有一个简单的方法。正如我所说,我以前没有使用过AspectJ,但我相信这是织布工的错误行为。

I am not sure that there is an easy way out of your problem. As I said I haven't worked with AspectJ before but I believe this is a mis-behaviour of the weaver.

问题描述:在启动过程中,代理会尝试将其他编织不仅应用于 WebAppClassLoader 但是整个类加载器链(每个类加载器一次)即: sun.misc.Launcher $ AppClassLoader sun.misc.Launcher $ ExtClassLoader org.apache.catalina.loader.StandardClassLoader (tomcat的类加载器)。当您使用 META-INF / aop.xml 方法时,它会禁用上述类加载器的编织,因为配置文件不可用(如果启用 verbose 模式,您可以在控制台中看到这些消息)。使用文件配置方法时,配置可用于链中的所有类加载器。由于它确实找到了配置文件,因此代理会解析定义,但它找不到方面的类并显示错误。

Problem description: During boot the agent tries to apply weaving other not only to the WebAppClassLoader but to the whole classloader chain (once per classloader) i.e. to: sun.misc.Launcher$AppClassLoader, sun.misc.Launcher$ExtClassLoader, org.apache.catalina.loader.StandardClassLoader (the tomcat's classloader). When you use the META-INF/aop.xml approach it disables weaving for the above classloaders because "a configuration file is not available" (if you enable verbose mode you can see those messages in console). When you use the file configuration approach, a configuration is available for all the classloaders in the chain. Since it does find a configuration file, the agent parses the definitions, it does not find the aspects' class and shows the error.

奇怪的是,正如配置文档,如果您使用 WeavingURLClassLoader 方法进行加载时间编织,...它还允许用户通过类加载器显式限制哪些类可以编织。所以这实际上是类加载器方法可以具有的功能(!),但代理方法却没有。 (不幸的是我无法使用这种方法)

The weird thing is that, as described in the configuration documentation if you use the WeavingURLClassLoader approach for load time weaving, "... it also allows the user to explicitly restrict by class loader which classes can be woven". So this is actually a feature (!) that the classloader approach can have but the agent approach doesn't. (Unfortunately I was not able to use this approach)

好消息(和坏消息):好消息是你可以轻松创建自己的代理,忽略上述类加载器的编织。坏消息是限制每个类加载器的编织是不够的,因为如果你在同一个服务器上有其他应用程序,Tomcat仍然会使用 WebAppClassLoader 来加载它们,这样你仍然会得到它们这些应用程序的错误消息。 (也许你可以扩展下面的类来过滤包/类,在这种情况下)。

The good (and the bad) news: The good news is that you can easily create your own agent that will ignore the weaving for the aforementioned classloaders. The bad news is that restricting weaving per classloader is not enough because if you have other applications in the same server, Tomcat would still use the WebAppClassLoader to load them so you would still get error messages for those applications. (Perhaps you could extend the classes below to filter packages/classes as well, in that case).

下面你可以找到两个修改过的代理类。要使用它们,您需要执行以下操作:

Below you can find two class for the modified agent. To use them you would need to do the following:


  • Un-jar aspectjweaver.jar 到一个文件夹

  • org / aspectj / weaver / loadtime 下创建一个新文件夹 filter 匹配包名并在编译后将两个新类放在那里。

  • 编辑 META-INF / MANIFEST .MF 文件并更改行

  • Un-jar the aspectjweaver.jar to a folder
  • Under org/aspectj/weaver/loadtime create a new folder filter to match the package name and put there the two new classes after you compile them.
  • Edit the META-INF/MANIFEST.MF file and change the line

Premain-Class:org.aspectj.weaver.loadtime.Agent to

Premain-Class:org.aspectj.weaver.loadtime.filter.FilterAgent

重新启动并准备好新代理。

Re-jar and you have your new agent ready.

这些类是原始代理的类的修改副本代理商 ClassPreProcessorAgentAdapter 。我添加的唯一代码是解析上述系统属性的部分(如果存在)并忽略对我们不感兴趣的类加载器的调用。

The classes are a modified copy of the original agent's classes Agent and ClassPreProcessorAgentAdapter. The only code I have added is the part that parses the above system property if it exists and to ignore calls for the classloaders we are not interested in.

自行使用风险:)我希望有帮助

Use at your own risk :) I hope that helps

package org.aspectj.weaver.loadtime.filter;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;

public class FilterAgent {

    private static Instrumentation s_instrumentation;

    // Use our own version of ClassFileTransformer that would filter out selected classloaders 
    private static ClassFileTransformer s_transformer = new ClassPreprocessorFilteredAdapter();

    /**
     * JSR-163 preMain Agent entry method
     *
     * @param options
     * @param instrumentation
     */
    public static void premain(String options, Instrumentation instrumentation) {
        /* Handle duplicate agents */
        if (s_instrumentation != null) {
            return;
        }
        s_instrumentation = instrumentation;
        s_instrumentation.addTransformer(s_transformer);
    }

    public static Instrumentation getInstrumentation() {
        if (s_instrumentation == null) {
            throw new UnsupportedOperationException("Java 5 was not started with preMain -javaagent for AspectJ");
        }
        return s_instrumentation;
    }
}
//-----------------------------------------------------------------------------------
package org.aspectj.weaver.loadtime.filter;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map;

import org.aspectj.weaver.loadtime.Aj;
import org.aspectj.weaver.loadtime.ClassPreProcessor;


public class ClassPreprocessorFilteredAdapter implements ClassFileTransformer {

    /**
     * Concrete preprocessor.
     */
    private static ClassPreProcessor s_preProcessor;

    private static Map<String, String> ignoredClassloaderNames = new HashMap<String, String>();

    static {
        try {
            s_preProcessor = new Aj();
            s_preProcessor.initialize();


            String ignoredLoaders = System.getProperty("org.aspectj.weaver.loadtime.filter", "");
            if (ignoredLoaders.length() > 0) {
                String[] loaders = ignoredLoaders.split(",");

                for (String s : loaders) {
                    s = s.trim();
                    ignoredClassloaderNames.put(s, s);
                    System.out.println("---> Will filtered out classloader: " + s);
                }
            }

        } catch (Exception e) {
            throw new ExceptionInInitializerError("could not initialize JSR163 preprocessor due to: " + e.toString());
        }
    }

    /**
     * Invokes the weaver to modify some set of input bytes.
     * 
     * @param loader the defining class loader
     * @param className the name of class being loaded
     * @param classBeingRedefined is set when hotswap is being attempted
     * @param protectionDomain the protection domain for the class being loaded
     * @param bytes the incoming bytes (before weaving)
     * @return the woven bytes
     */
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
        if (classBeingRedefined != null) {
            System.err.println("INFO: (Enh120375):  AspectJ attempting reweave of '" + className + "'");
        }

        String loaderName = loader.getClass().getName();
        if (shouldIgnoreClassLoader(loaderName)) {
            return bytes;
        }
        return s_preProcessor.preProcess(className, bytes, loader, protectionDomain);
    }

    private boolean shouldIgnoreClassLoader(String loaderName) {
        boolean result = false;
        String ignoredLoader = ignoredClassloaderNames.get(loaderName);
        if (ignoredLoader != null) {
            result = true;    // if the loader name exists in the map we will ignore weaving
        }
        return result;
    }
}

这篇关于AspectJ:尝试使用外部aop.xml文件时出现ClassLoading问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆