java - AspectJ: ClassLoading issue when trying to use external aop.xml file -
i m trying externalize configuration of aop.xml removed aop.xml
meta-inf
, made available in server manual configuration sys admins.
when try use external aop.xml using
-dorg.aspectj.weaver.loadtime.configuration="file:d:\workspace\tomcat7\shared\lib\aop.xml"
i java.lang.runtimeexception: cannot register non aspect: aspectclass....
because aj casses not loaded appclassloader
yet @ time. , next time tries register aspects webappclassloader
( after classes loaded), works fine, still exceptions logged 1st attempt register it.
the exception caught , logged @ classloaderweavingadaptor.java
line 307.
when following line called: success = registeraspects(weaver, loader, definitions);
the exception caught , logged.
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); }
the exception thrown excactly in following line in bcelweaver.java
if (type.isaspect()) { ...... } else { // fixme av - better warning upon no such aspect aop.xml runtimeexception ex = new runtimeexception("cannot register non aspect: " + type.getname() + " , " + aspectname); if (trace.istraceenabled()) { trace.exit("addlibraryaspect", ex); } throw ex; }
how can prevent classloader logging error console, when aspects not loaded yet. thinking of commenting line logs exception source file , rebuilding aspectjweaver jar file, looking better solution without modifying aspectj source.
i not sure there easy way out of problem. said haven't worked aspectj before believe mis-behaviour of weaver.
problem description: during boot agent tries apply weaving other not webappclassloader
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 use meta-inf/aop.xml
approach disables weaving above classloaders because "a configuration file not available" (if enable verbose
mode can see messages in console). when use file configuration approach, configuration is available classloaders in chain. since find configuration file, agent parses definitions, not find aspects' class , shows error.
the weird thing that, described in configuration documentation if use weavingurlclassloader
approach load time weaving, "... allows user explicitly restrict class loader classes can woven". feature (!) classloader approach can have agent approach doesn't. (unfortunately not able use approach)
the (and bad) news: news can create own agent ignore weaving aforementioned classloaders. bad news restricting weaving per classloader not enough because if have other applications in same server, tomcat still use webappclassloader
load them still error messages applications. (perhaps extend classes below filter packages/classes well, in case).
below can find 2 class modified agent. use them need following:
- un-jar
aspectjweaver.jar
folder - under
org/aspectj/weaver/loadtime
create new folderfilter
match package name , put there 2 new classes after compile them. edit
meta-inf/manifest.mf
file , change linepremain-class: org.aspectj.weaver.loadtime.agent
to
premain-class: org.aspectj.weaver.loadtime.filter.filteragent
re-jar , have new agent ready.
- when starting jvm can pass new system property comma separated list of classloaders ignore i.e.
-dorg.aspectj.weaver.loadtime.filter=sun.misc.launcher$appclassloader,sun.misc.launcher$extclassloader,org.apache.catalina.loader.standardclassloader
( have setcatalina_opts
that).
the classes modified copy of original agent's classes agent
, classpreprocessoragentadapter
. code have added part parses above system property if exists , ignore calls classloaders not interested in.
use @ own risk :) hope 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 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 not started premain -javaagent 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(","); (string s : loaders) { s = s.trim(); ignoredclassloadernames.put(s, s); system.out.println("---> filtered out classloader: " + s); } } } catch (exception e) { throw new exceptionininitializererror("could not initialize jsr163 preprocessor due to: " + e.tostring()); } } /** * invokes weaver modify set of input bytes. * * @param loader defining class loader * @param classname name of class being loaded * @param classbeingredefined set when hotswap being attempted * @param protectiondomain protection domain class being loaded * @param bytes incoming bytes (before weaving) * @return 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 loader name exists in map ignore weaving } return result; } }
Comments
Post a Comment