美文网首页
load-time-weaver源码分析--aop.xml解析部

load-time-weaver源码分析--aop.xml解析部

作者: 悟空嘿 | 来源:发表于2019-10-18 11:04 被阅读0次

load-time-weaver源码分析--aop.xml解析部分

备注:spring解析META-INF/aop.xml,MATE-INF/acj-aop.xml,org/aspectj/aop.xml 文件,作为切面类,拦截相应的方法,然后为目标类的目标方法,加入切面逻辑。

1.根据java 提供的Instrumentation用户可以制作自己的agent。

spring将InstrumentationSavingAgent作为jvm参数专递给jvm,jvm会调用premain(..)为其分配一个Instrumentation实例,然后spring拿到Instrumentation实例后,使用addTransformer(..)方法,添加自定义的transformer转换类,转换的逻辑主要实在transformer#transform方法中,用来实现自定义的切面逻辑。AspectJ的transformer类主要是ClassPreProcessorAgentAdapter,而ClassPreProcessorAgentAdapter本身也是个包装类。网上多半分析到这里为止,我将后续源码分析记录下来,以备后续查看。

另外,类加载,xml文件加载不是很好debug,但是可以开启 trace 的traceEnabled属性,跟踪运行的日志信息,方便分析源码。设置方式:添加jvm参数 -Dorg.aspectj.tracing.enabled=true

1.ClassPreProcessorAgentAdapter#transform

//ClassPreProcessorAgentAdapter
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 + "'");
        }
        // 代理专递给 Aj#preProcess 方法
        return s_preProcessor.preProcess(className, bytes, loader, protectionDomain);
    }

2.Aj#preProcess

//@see Aj#preProcess
public byte[] preProcess(String className, byte[] bytes, ClassLoader loader, ProtectionDomain protectionDomain) {
      // TODO AV needs to doc that
      if (loader == null || className == null || loader.getClass().getName().equals(deleLoader)) {
         // skip boot loader, null classes (hibernate), or those from a reflection loader
         return bytes;
      }
      
      if (loadersToSkip != null) {
         // Check whether to reject it
         if (loadersToSkip.contains(loader.getClass().getName())) {
//          System.out.println("debug: no weaver created for loader '"+loader.getClass().getName()+"'");
            return bytes;
         }
      }
    // trace.isTraceEnabled,设置为true,方便跟踪代码运行信息
      if (trace.isTraceEnabled())
         trace.enter("preProcess", this, new Object[] { className, bytes, loader });
      if (trace.isTraceEnabled())
         trace.event("preProcess", this, new Object[] { loader.getParent(), Thread.currentThread().getContextClassLoader() });

      try {
         synchronized (loader) {

            if (SimpleCacheFactory.isEnabled()) {
               byte[] cacheBytes= laCache.getAndInitialize(className, bytes,loader,protectionDomain);
               if (cacheBytes!=null){
                     return cacheBytes;
               }
            }
            // 查找相应切面方法,加入
            WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext);
            if (weavingAdaptor == null) {
               if (trace.isTraceEnabled())
                  trace.exit("preProcess");
               return bytes;
            }
            try {
               weavingAdaptor.setActiveProtectionDomain(protectionDomain);
               byte[] newBytes = weavingAdaptor.weaveClass(className, bytes, false);
               Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true);
               if (trace.isTraceEnabled())
                  trace.exit("preProcess", newBytes);
               if (SimpleCacheFactory.isEnabled()) {
                  laCache.put(className, bytes, newBytes);
               }
               return newBytes;
            } finally {
               weavingAdaptor.setActiveProtectionDomain(null);
            }
         }

         /* Don't like to do this but JVMTI swallows all exceptions */
      } catch (Throwable th) {
         trace.error(className, th);
         Dump.dumpWithException(th);
         // FIXME AV wondering if we should have the option to fail (throw runtime exception) here
         // would make sense at least in test f.e. see TestHelper.handleMessage()
         if (trace.isTraceEnabled())
            trace.exit("preProcess", th);
         return bytes;
      } finally {
         CompilationAndWeavingContext.resetForThread();
      }
   }


// 3. @see WeaverContainer#getWeaver 方法,
static WeavingAdaptor getWeaver(ClassLoader loader, IWeavingContext weavingContext) {
            ExplicitlyInitializedClassLoaderWeavingAdaptor adaptor = null;
            AdaptorKey adaptorKey = new AdaptorKey(loader);

            String loaderClassName = loader.getClass().getName();

            synchronized (weavingAdaptors) {
                checkQ();
                if (loader.equals(myClassLoader)){
                    adaptor = myClassLoaderAdaptor;
                } else {
                    adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey);
                }
                if (adaptor == null) {
                    // create it and put it back in the weavingAdaptors map but avoid any kind of instantiation
                    // within the synchronized block
                    ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor();
                    adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor);
                      if(myClassLoaderAdaptor == null && loader.equals(myClassLoader)){
                            myClassLoaderAdaptor = adaptor;
                      } else {
                            weavingAdaptors.put(adaptorKey, adaptor);
                      }
                }
            }
            // perform the initialization
            // 找到配置切面类,作为适配器
            return adaptor.getWeavingAdaptor(loader, weavingContext);
        }


//4. @see ExplicitlyInitializedClassLoaderWeavingAdaptor#getWeavingAdaptor
public ClassLoaderWeavingAdaptor getWeavingAdaptor(ClassLoader loader, IWeavingContext weavingContext) {
            initialize(loader, weavingContext);
            return weavingAdaptor;
        }
//5. @see ClassLoaderWeavingAdaptor#initialize
public void initialize(final ClassLoader classLoader, IWeavingContext context) {
        if (initialized) {
            return;
        }

        boolean success = true;

        this.weavingContext = context;
        if (weavingContext == null) {
            weavingContext = new DefaultWeavingContext(classLoader);
        }

        createMessageHandler();

        this.generatedClassHandler = new SimpleGeneratedClassHandler(classLoader);

        List definitions = weavingContext.getDefinitions(classLoader, this);
        if (definitions.isEmpty()) {
            disable(); // TODO maw Needed to ensure messages are flushed
            if (trace.isTraceEnabled()) {
                trace.exit("initialize", definitions);
            }
            return;
        }

        // TODO when the world works in terms of the context, we can remove the loader
        bcelWorld = new LTWWorld(classLoader, weavingContext, getMessageHandler(), null);

        weaver = new BcelWeaver(bcelWorld);

        // register the definitions
        //注册 Definition,最主要的是 registerAspects(weaver, loader, definitions);
        //将definition中的@Aspect类解析,并将切点作为拦截依据,执行是否生成新的 class文件(以byte[]数组的形式使用)// 注册拦截的代码,后续再分析
        success = registerDefinitions(weaver, classLoader, definitions);
        if (success) {

            // after adding aspects
            weaver.prepareForWeave();

            enable(); // TODO maw Needed to ensure messages are flushed
            success = weaveAndDefineConceteAspects();
        }

        if (success) {
            enable();
        } else {
            disable();
            bcelWorld = null;
            weaver = null;
        }
        if (WeavedClassCache.isEnabled()) {
            initializeCache(classLoader, getAspectClassNames(definitions), generatedClassHandler, getMessageHandler());
        }

        initialized = true;
        if (trace.isTraceEnabled()) {
            trace.exit("initialize", isEnabled());
        }
    }

//@see org.aspectj.weaver.loadtime.DefaultWeavingContext#getDefinitions
    public List<Definition> getDefinitions(final ClassLoader loader, final WeavingAdaptor adaptor) {
        if (trace.isTraceEnabled()) {
            trace.enter("getDefinitions", this, new Object[] { "goo", adaptor });
        }
        // 查找切面的bean定义类,允许多个
        List<Definition> definitions = ((ClassLoaderWeavingAdaptor) adaptor).parseDefinitions(loader);

        if (trace.isTraceEnabled()) {
            trace.exit("getDefinitions", definitions);
        }
        return definitions;
    }
}
//6. @see org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor#parseDefinitions
List<Definition> parseDefinitions(final ClassLoader loader) {
   if (trace.isTraceEnabled()) {
      trace.enter("parseDefinitions", this);
   }

   List<Definition> definitions = new ArrayList<Definition>();
   try {
      info("register classloader " + getClassLoaderName(loader));
      // TODO av underoptimized: we will parse each XML once per CL that see it

      // TODO av dev mode needed ? TBD -Daj5.def=...
      if (loader.equals(ClassLoader.getSystemClassLoader())) {
         String file = System.getProperty("aj5.def", null);
         if (file != null) {
            info("using (-Daj5.def) " + file);
            definitions.add(DocumentParser.parse((new File(file)).toURL()));
         }
      }
        // 默认的filePath:以下 3种文件形式
       // AOP_XML = Constants.AOP_USER_XML + ";" + Constants.AOP_AJC_XML + ";" + Constants.AOP_OSGI_XML;
       // AOP_USER_XML = "META-INF/aop.xml";AOP_AJC_XML = "META-INF/aop-ajc.xml";
       // AOP_OSGI_XML = "org/aspectj/aop.xml";       
      String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration", AOP_XML);
      if (trace.isTraceEnabled()) {
         trace.event("parseDefinitions", this, resourcePath);
      }

      StringTokenizer st = new StringTokenizer(resourcePath, ";");

      while (st.hasMoreTokens()) {
         String nextDefinition = st.nextToken();
         if (nextDefinition.startsWith("file:")) {
            try {
               String fpath = new URL(nextDefinition).getFile();
               // 加载文件
                File configFile = new File(fpath);
               if (!configFile.exists()) {
                  warn("configuration does not exist: " + nextDefinition);
               } else {
                   // 读取文件,并转化为
                  definitions.add(DocumentParser.parse(configFile.toURL()));
               }
            } catch (MalformedURLException mue) {
               error("malformed definition url: " + nextDefinition);
            }
         } else {
            Enumeration<URL> xmls = weavingContext.getResources(nextDefinition);
            // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader);

            Set<URL> seenBefore = new HashSet<URL>();
            while (xmls.hasMoreElements()) {
               URL xml = xmls.nextElement();
               if (trace.isTraceEnabled()) {
                  trace.event("parseDefinitions", this, xml);
               }
               if (!seenBefore.contains(xml)) {
                  info("using configuration " + weavingContext.getFile(xml));
                  definitions.add(DocumentParser.parse(xml));
                  seenBefore.add(xml);
               } else {
                  debug("ignoring duplicate definition: " + xml);
               }
            }
         }
      }
      if (definitions.isEmpty()) {
         info("no configuration found. Disabling weaver for class loader " + getClassLoaderName(loader));
      }
   } catch (Exception e) {
      definitions.clear();
      warn("parse definitions failed", e);
   }

   if (trace.isTraceEnabled()) {
      trace.exit("parseDefinitions", definitions);
   }
   return definitions;
}

相关文章

网友评论

      本文标题:load-time-weaver源码分析--aop.xml解析部

      本文链接:https://www.haomeiwen.com/subject/xadzbqtx.html