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;
}
网友评论