解压缩后,在其META-INF/MANIFEST.MF中,我们看到了如下内容:
Manifest-Version: 1.0 Name: org/aspectj/weaver/ Specification-Title: AspectJ Weaver Classes Specification-Version: 1.8.2 Specification-Vendor: aspectj.org Implementation-Title: org.aspectj.weaver Implementation-Version: 1.8.2 Implementation-Vendor: aspectj.org Premain-Class: org.aspectj.weaver.loadtime.Agent 这个地方重点关注,这个是指定main执行前要执行的类 Can-Redefine-Classes: true上面我们看到,其指定了:
Premain-Class: org.aspectj.weaver.loadtime.Agent那么我们看看这个类:
/** * Java 1.5 preMain agent to hook in the class pre processor * Can be used with -javaagent:aspectjweaver.jar * */ public class Agent { /** * The instrumentation instance */ private static Instrumentation s_instrumentation; /** * The ClassFileTransformer wrapping the weaver */ private static ClassFileTransformer s_transformer = new ClassPreProcessorAgentAdapter(); /** * JSR-163 preMain Agent entry method * 敲黑板,这个premain的方法签名是定死了的,和我们main方法类似。其中,参数instrumentation是由JVM传进来的 * @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); } /** * Returns the Instrumentation system level instance */ public static Instrumentation getInstrumentation() { if (s_instrumentation == null) { throw new UnsupportedOperationException("Java 5 was not started with preMain -javaagent for AspectJ"); } return s_instrumentation; } }别的我也不多说,多的我也不懂,只要大家明白,这里premain会在main方法执行前执行,且这里的instrumentation由JVM传入,且这里通过执行:
s_instrumentation.addTransformer(s_transformer);给JVM注入了一个字节码转换器。
这个字节码转换器的类型是,ClassPreProcessorAgentAdapter。
这个类里面呢,翻来覆去,代码很复杂,但是大家想也知道,无非是去aop.xml文件里,找到要使用的Aspect切面。切面里面定义了切点和切面逻辑。拿到这些后,就可以对目标class进行转换了。
我大概翻了代码,解析aop.xml的代码在:org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor类中。
// aop文件的名称 private final static String AOP_XML = "META-INF/aop.xml"; /** * 加载aop.xml * Load and cache the aop.xml/properties according to the classloader visibility rules * * @param loader */ List<Definition> parseDefinitions(final ClassLoader loader) { List<Definition> definitions = new ArrayList<Definition>(); try { String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration", AOP_XML); StringTokenizer st = new StringTokenizer(resourcePath, ";"); while (st.hasMoreTokens()) { String nextDefinition = st.nextToken(); ... 这里面是具体的解析 } } ... return definitions; } AspectJ的LTW的劣势优势我就不多说了,大家可以自由发挥,比如大家熟知的性能监控啥的,基本都是基于这个来做的。
劣势是啥?大家发现了吗,我们总是需要在启动时,指定-javaagent参数,就像下面这样:
java -javaagent:aspectjweaver-1.8.2.jar -cp java-aspectj-agent-1.0-SNAPSHOT.jar foo.Main大概有以下问题:
很多时候,部署是由运维去做的,开发不能做到只给一个jar包,还得让运维去加参数,要是运维忘了呢?风险很大;
假设我们要进行ltw的是一个tomcat的webapp应用,但这个tomcat同时部署了好几个webapp,但是另外几个webapp其实是不需要被ltw的,但是么办法啊,粒度就是这么粗。
基于以上问题,出现了spring的基于aspectJ进行了优化的,粒度更细的LTW。
具体我下节再讲。
总结本来是打算讲清楚spring的context:load-time-weaver,无奈内容太多了,只能下节继续。今天内容到这,谢谢大家。源码我是和spring这个系列放一块的,其实今天的代码比较独立,大家可以加我,我单独发给大家也可以。