相關背景及資源:html
曹工說Spring Boot源碼(1)-- Bean Definition究竟是什麼,附spring思惟導圖分享java
曹工說Spring Boot源碼(2)-- Bean Definition究竟是什麼,我們對着接口,逐個方法講解git
曹工說Spring Boot源碼(3)-- 手動註冊Bean Definition不比遊戲好玩嗎,咱們來試一下web
曹工說Spring Boot源碼(4)-- 我是怎麼自定義ApplicationContext,從json文件讀取bean definition的?spring
曹工說Spring Boot源碼(5)-- 怎麼從properties文件讀取beanshell
曹工說Spring Boot源碼(6)-- Spring怎麼從xml文件裏解析bean的apache
曹工說Spring Boot源碼(7)-- Spring解析xml文件,到底從中獲得了什麼(上)json
曹工說Spring Boot源碼(8)-- Spring解析xml文件,到底從中獲得了什麼(util命名空間)tomcat
曹工說Spring Boot源碼(9)-- Spring解析xml文件,到底從中獲得了什麼(context命名空間上)app
曹工說Spring Boot源碼(10)-- Spring解析xml文件,到底從中獲得了什麼(context:annotation-config 解析)
曹工說Spring Boot源碼(11)-- context:component-scan,你真的會用嗎(此次來講說它的奇技淫巧)
曹工說Spring Boot源碼(12)-- Spring解析xml文件,到底從中獲得了什麼(context:component-scan完整解析)
曹工說Spring Boot源碼(13)-- AspectJ的運行時織入(Load-Time-Weaving),基本內容是講清楚了(附源碼)
曹工說Spring Boot源碼(14)-- AspectJ的Load-Time-Weaving的兩種實現方式細細講解,以及怎麼和Spring Instrumentation集成
工程結構圖:
本篇是spring源碼的第15篇,前面13/14兩篇,重點講了load-time-weaver的使用和底層原理。load-time-weaver,通俗地說,就是在JVM加載class時作文章,原本加載一個class A,可是實際JVM加載的class A,多是被加強過的,被修改過的,因此,這是一種應用面更廣,適用場景更多的,性能也更加優秀的aop方案,避免了運行時aop的性能消耗。
使用demo,我這邊有兩個:
tomcat war包場景:
https://gitee.com/ckl111/all-simple-demo-in-work/tree/master/test-load-time-weaver
本應用爲war包應用,ide裏使用tomcat啓動便可,訪問:
http://localhost:20000/test.do (端口修改成本身的)。
訪問上述url後,能夠看到效果:
java獨立應用場景:
https://gitee.com/ckl111/all-simple-demo-in-work/tree/master/spring-load-time-weave-demo
本應用爲獨立應用,直接啓動foo.Main中的main方法便可。
值得注意的是,此時啓動時,須要指定:-javaagent:E:\repo\org\springframework\spring-instrument\4.3.7.RELEASE\spring-instrument-4.3.7.RELEASE.jar
執行main方法後,效果以下:
代碼我就不仔細拉下來說了,和前面1三、14兩講差很少。
上面兩個demo,都是在spring的配置文件裏,進行了以下配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> // 運行時加載的核心,就在於此 <context:load-time-weaver/> </beans>
咱們知道,解析context命名空間的,主要是org.springframework.context.config.ContextNamespaceHandler
。
package org.springframework.context.config; public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); // 這個就是咱們要找的 registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }
從上述init方法中,能夠看出,解析load-time-weaver元素的類爲:LoadTimeWeaverBeanDefinitionParser。
該類的類結構以下,能夠看到,實現了BeanDefinitionParser
,這個接口的方法,很簡單,就是給你一個xml元素,你負責解析BeanDefinition。
import org.w3c.dom.Element; import org.springframework.beans.factory.config.BeanDefinition; public interface BeanDefinitionParser { BeanDefinition parse(Element element, ParserContext parserContext); }
咱們如今看下本解析類的實現:
@Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 判斷aspectJ織入是否啓用,通常來講,只要classpath下存在META-INF/aop.xml,就算作啓用 if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) { if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) { // 註冊一個bean,bean的class爲ASPECTJ_WEAVING_ENABLER_CLASS_NAME常量,該常量爲:org.springframework.context.weaving.AspectJWeavingEnabler RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME); parserContext.registerBeanComponent( new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME)); } if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) { new SpringConfiguredBeanDefinitionParser().parse(element, parserContext); } } } // 判斷aspectJ織入是否啓用,通常來講,只要classpath下存在META-INF/aop.xml,就算作啓用 protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) { if ("on".equals(value)) { return true; } else if ("off".equals(value)) { return false; } else { ClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader(); return (cl.getResource("META-INF/aop.xml") != null); } }
咱們從上面這段代碼,能夠看到,doParse時,註冊了一個beanDefinition,該beanDefinition的class爲:
org.springframework.context.weaving.AspectJWeavingEnabler。
其實,這段代碼總共會註冊2個bean definition:
doParse方法的參數BeanDefinitionBuilder builder,你們看到了吧,這個參數是父類傳進來的,最終會被註冊爲一個bean definition,這個bean的class是啥呢,能夠看到下面的代碼,獲取class是調用了子類的getBeanClassName。
// 本類爲上述解析類LoadTimeWeaverBeanDefinitionParser的父類 org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser @Override protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); String parentName = getParentName(element); if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } // 調用子類的方法,獲取bean class String beanClassName = getBeanClassName(element); if (beanClassName != null) { builder.getRawBeanDefinition().setBeanClassName(beanClassName); } // 就是這裏,會把builder傳給子類進行處理; doParse(element, parserContext, builder); // 這裏會經過builder,獲取到BeanDefinition,返回給上層去註冊 return builder.getBeanDefinition(); }
// 被父類調用,獲取bean class,這裏返回的class爲:首先看看xml元素是否設置了該屬性,若是沒設置,返回默認class:org.springframework.context.weaving.DefaultContextLoadTimeWeaver @Override protected String getBeanClassName(Element element) { if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) { return element.getAttribute(WEAVER_CLASS_ATTRIBUTE); } return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME; }
你們在前面看到了,除了上面註冊的這個bean definition,在LoadTimeWeaverBeanDefinitionParser的doParse裏,還註冊了一個bean definition,類型爲org.springframework.context.weaving.AspectJWeavingEnabler。
原本可能還會註冊一個,這個暫時不太瞭解,先跳過:
@Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) { if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME); parserContext.registerBeanComponent( new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME)); } // 這裏若是知足,還會自動註冊<context:spring-configured/> if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) { new SpringConfiguredBeanDefinitionParser().parse(element, parserContext); } } }
彙總一下,註冊了2個bean definition,其中一個爲特殊類型的bean
bean class | bean 類型 | 實現的接口 |
---|---|---|
DefaultContextLoadTimeWeaver | 普通bean | LoadTimeWeaver,BeanClassLoaderAware |
AspectJWeavingEnabler | 實現了BeanFactoryPostProcessor,會在spring獲取完成所有的bean definition後,會全部的bean definition進行後置處理 | BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, |
上面咱們看到,註冊的兩個bean,其中一個比較特殊,是實現了BeanFactoryPostProcessor接口的。
按理說,正常的流程是:
但還有個問題,既然第二步中,BeanFactoryPostProcessor要去處理spring中全部的bean definition,那,BeanFactoryPostProcessor要怎麼生成呢?
不用擔憂,BeanFactoryPostProcessor 它本身也是bean definition,生成的話,也是走和普通bean definition同樣的流程。只是,BeanFactoryPostProcessor這些bean 的生成的時機比較超前。
下面這個代碼,你們確定比較熟悉了:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // BeanFactoryPostProcessor 這種類型的bean,在此時發揮做用,這時,就會經過getBean來先進行它自身的實例化 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } } }
在上述的 invokeBeanFactoryPostProcessors(beanFactory)中,中間會調用到下面的代碼:
#org.springframework.context.support.PostProcessorRegistrationDelegate public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // 獲取各類BeanFactoryPostProcessor ... String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); ... // 這裏,遍歷全部的BeanFactoryPostProcessor,對每一個BeanFactoryPostProcessor進行getBean來實例化 List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); ... beanFactory.clearMetadataCache(); }
這裏,咱們只關注咱們前文經過context:load-time-weaver解析到的那個AspectJWeavingEnabler:
public class AspectJWeavingEnabler implements BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered
它實現了BeanClassLoaderAware,spring會把當前使用的類加載器傳給這個bean;
它實現了LoadTimeWeaverAware,spring會給它傳遞一個LoadTimeWeaver:
public interface LoadTimeWeaverAware extends Aware { void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver); }
調用setLoadTimeWeaver傳遞LoadTimeWeaver,發生在何時呢?
其實,這個操做是由org.springframework.context.weaving.LoadTimeWeaverAwareProcessor來完成的,這個類,是一個BeanPostProcessor,既然是BeanPostProcessor,就是在bean已經生成了以後,實例化以前。
也就是說,在AspectJWeavingEnabler這個bean被建立後,可是尚未實例化以前,會調用BeanPostProcessor來對bean進行處理;其中一個BeanPostProcessor就是LoadTimeWeaverAwareProcessor。
咱們接下來看LoadTimeWeaverAwareProcessor的實現:
org.springframework.context.weaving.LoadTimeWeaverAwareProcessor @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof LoadTimeWeaverAware) { LoadTimeWeaver ltw = this.loadTimeWeaver; if (ltw == null) { // 經過spring 的beanFactory去獲取LoadTimeWeaver bean ltw = this.beanFactory.getBean( ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class); } // 這裏,會把LoadTimeWeaver bean,設置給AspectJWeavingEnabler 這個bean ((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw); } return bean; }
上面,咱們看到了,在LoadTimeWeaverAwareProcessor 裏,要去經過getBean(LoadTimeWeaver.class)來獲取LoadTimeWeaver。
咱們知道,這個bean definition已經在解析context:load-time-weaver時註冊了,其類型爲:
DefaultContextLoadTimeWeaver,這個bean class不特別,一個普通bean,實現了LoadTimeWeaver接口,還實現了一個生命週期接口:BeanClassLoaderAware
// 須要感知BeanClassLoader,所以實現了BeanClassLoaderAware public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLoaderAware, DisposableBean public interface BeanClassLoaderAware extends Aware { void setBeanClassLoader(ClassLoader classLoader); }
咱們先看看其實現的功能接口LoadTimeWeaver:
public interface LoadTimeWeaver { // 這個方法,咱們能夠傳:類字節碼轉換器;也就是說,切面的那些邏輯,就是封裝爲ClassFileTransformer傳遞進去 void addTransformer(ClassFileTransformer transformer); ClassLoader getInstrumentableClassLoader(); }
咱們再看看它的setBeanClassLoader方法,有什麼特別的沒:
@Override public void setBeanClassLoader(ClassLoader classLoader) { // 根據classloader來建立容器相關的 LoadTimeWeaver LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader); if (serverSpecificLoadTimeWeaver != null) { if (logger.isInfoEnabled()) { logger.info("Determined server-specific load-time weaver: " + serverSpecificLoadTimeWeaver.getClass().getName()); } this.loadTimeWeaver = serverSpecificLoadTimeWeaver; } else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) { logger.info("Found Spring's JVM agent for instrumentation"); this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader); } else { try { this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader); logger.info("Using a reflective load-time weaver for class loader: " + this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName()); } catch (IllegalStateException ex) { throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " + "Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar"); } } }
這個方法,其實很關鍵,這裏就會根據當前的classloader,來判斷當前屬於哪一個容器環境。這個邏輯在createServerSpecificLoadTimeWeaver裏,若是當前classloader的名字,以org.apache.catalina開頭,說明當前是在tomcat裏運行,就會建立tomcat的相應實現類的實例。
protected LoadTimeWeaver createServerSpecificLoadTimeWeaver(ClassLoader classLoader) { String name = classLoader.getClass().getName(); try { if (name.startsWith("weblogic")) { return new WebLogicLoadTimeWeaver(classLoader); } else if (name.startsWith("org.glassfish")) { return new GlassFishLoadTimeWeaver(classLoader); } // 若是當前classloader的名字,以org.apache.catalina開頭,說明當前是在tomcat裏運行 else if (name.startsWith("org.apache.catalina")) { return new TomcatLoadTimeWeaver(classLoader); } else if (name.startsWith("org.jboss")) { return new JBossLoadTimeWeaver(classLoader); } else if (name.startsWith("com.ibm")) { return new WebSphereLoadTimeWeaver(classLoader); } } catch (IllegalStateException ex) { logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage()); } return null; }
你們能夠看看類圖:
因此,你們看到,LoadTimeWeaver有多種實現,前面就會根據當前classloader的名稱(好比在tomcat時,當前線程的classloader是org.apache.catalina.loader.WebappClassLoader,來建立LoadTimeWeaver在tomcat下的實現類TomcatLoadTimeWeaver的實例)
若是是獨立的java應用,則會建立InstrumentationLoadTimeWeaver 這種實現類的實例,供後續使用。
通過上面的講解,咱們獲取到了LoadTimeWeaver bean,最終呢,這個bean也會設置到AspectJWeavingEnabler 裏面。
爲啥呢,由於AspectJWeavingEnabler實現了 LoadTimeWeaverAware的,還記得吧。
public class AspectJWeavingEnabler implements BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered
那麼,一切就緒,咱們看看這個BeanFactoryPostProcessor是怎麼處理spring 的bean definition的。
public class AspectJWeavingEnabler implements BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered { private ClassLoader beanClassLoader; private LoadTimeWeaver loadTimeWeaver; public static final String ASPECTJ_AOP_XML_RESOURCE = "META-INF/aop.xml"; public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) { this.loadTimeWeaver = loadTimeWeaver; } // ok,就是這裏 @override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { //調用 enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader); } public static void enableAspectJWeaving(LoadTimeWeaver weaverToUse, ClassLoader beanClassLoader) { // 這裏,由於weaverToUse已是有值了,因此,會直接進入下面去 if (weaverToUse == null) { if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) { weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader); } else { throw new IllegalStateException("No LoadTimeWeaver available"); } } // 針對注入進來的LoadTimeWeaver,調用它的addTransformer,把aspectJ的ClassFileTransformer設置進去 weaverToUse.addTransformer(new AspectJClassBypassingClassFileTransformer( new ClassPreProcessorAgentAdapter())); }
這裏的weaverToUse,咱們知道,就是前面說的DefaultContextLoadTimeWeaver。
咱們看看DefaultContextLoadTimeWeaver的addTransformer方法,發現它代理給了具體的LoadTimeWeaver:
public void addTransformer(ClassFileTransformer transformer) { this.loadTimeWeaver.addTransformer(transformer); }
假設咱們是在tomcat模式下運行,這裏實際調用的,就是tomcat的實現類:
public class TomcatLoadTimeWeaver implements LoadTimeWeaver { private static final String INSTRUMENTABLE_LOADER_CLASS_NAME = "org.apache.tomcat.InstrumentableClassLoader"; private final ClassLoader classLoader; private final Method addTransformerMethod; private final Method copyMethod; public TomcatLoadTimeWeaver() { this(ClassUtils.getDefaultClassLoader()); } public TomcatLoadTimeWeaver(ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); this.classLoader = classLoader; Class<?> instrumentableLoaderClass; try { instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_LOADER_CLASS_NAME); if (!instrumentableLoaderClass.isInstance(classLoader)) { // Could still be a custom variant of a convention-compatible ClassLoader instrumentableLoaderClass = classLoader.getClass(); } } catch (ClassNotFoundException ex) { // We're on an earlier version of Tomcat, probably with Spring's TomcatInstrumentableClassLoader instrumentableLoaderClass = classLoader.getClass(); } try { this.addTransformerMethod = instrumentableLoaderClass.getMethod("addTransformer", ClassFileTransformer.class); // Check for Tomcat's new copyWithoutTransformers on InstrumentableClassLoader first Method copyMethod = ClassUtils.getMethodIfAvailable(instrumentableLoaderClass, "copyWithoutTransformers"); if (copyMethod == null) { // Fallback: expecting TomcatInstrumentableClassLoader's getThrowawayClassLoader copyMethod = instrumentableLoaderClass.getMethod("getThrowawayClassLoader"); } this.copyMethod = copyMethod; } catch (Throwable ex) { throw new IllegalStateException( "Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available", ex); } } @Override public void addTransformer(ClassFileTransformer transformer) { this.addTransformerMethod.invoke(this.classLoader, transformer); } }
其實,這裏的addTransformer實現,就是調用了addTransformerMethod 這個method,這個method呢,其實就是:
org.apache.tomcat.InstrumentableClassLoader.addTransformerMethod (ClassFileTransformer transformer)方法,有興趣你們能夠翻到第14篇看一下,裏面很詳細介紹了tomcat的實現細節。
此時的實現類,就是InstrumentationLoadTimeWeaver。
public class InstrumentationLoadTimeWeaver implements LoadTimeWeaver { private static final boolean AGENT_CLASS_PRESENT = ClassUtils.isPresent( "org.springframework.instrument.InstrumentationSavingAgent", InstrumentationLoadTimeWeaver.class.getClassLoader()); private final ClassLoader classLoader; private final Instrumentation instrumentation; private final List<ClassFileTransformer> transformers = new ArrayList<ClassFileTransformer>(4); /** * Create a new InstrumentationLoadTimeWeaver for the default ClassLoader. */ public InstrumentationLoadTimeWeaver() { this(ClassUtils.getDefaultClassLoader()); } /** * Create a new InstrumentationLoadTimeWeaver for the given ClassLoader. * @param classLoader the ClassLoader that registered transformers are supposed to apply to */ public InstrumentationLoadTimeWeaver(ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); this.classLoader = classLoader; this.instrumentation = getInstrumentation(); } @Override public void addTransformer(ClassFileTransformer transformer) { FilteringClassFileTransformer actualTransformer = new FilteringClassFileTransformer(transformer, this.classLoader); synchronized (this.transformers) { if (this.instrumentation == null) { throw new IllegalStateException( "Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation."); } this.instrumentation.addTransformer(actualTransformer); this.transformers.add(actualTransformer); } } /** * Obtain the Instrumentation instance for the current VM, if available. * @return the Instrumentation instance, or {@code null} if none found * @see #isInstrumentationAvailable() */ private static Instrumentation getInstrumentation() { if (AGENT_CLASS_PRESENT) { return InstrumentationAccessor.getInstrumentation(); } else { return null; } } /** * Inner class to avoid InstrumentationSavingAgent dependency. */ private static class InstrumentationAccessor { public static Instrumentation getInstrumentation() { return InstrumentationSavingAgent.getInstrumentation(); } } /** * Decorator that only applies the given target transformer to a specific ClassLoader. */ private static class FilteringClassFileTransformer implements ClassFileTransformer { private final ClassFileTransformer targetTransformer; private final ClassLoader targetClassLoader; public FilteringClassFileTransformer(ClassFileTransformer targetTransformer, ClassLoader targetClassLoader) { this.targetTransformer = targetTransformer; this.targetClassLoader = targetClassLoader; } @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (!this.targetClassLoader.equals(loader)) { return null; } return this.targetTransformer.transform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer); } } }
核心就兩點,若是啓動時,加了下面的參數
-javaagent:E:\repo\org\springframework\spring-instrument\4.3.7.RELEASE\spring-instrument-4.3.7.RELEASE.jar
下面這個語句就是true,org.springframework.instrument.InstrumentationSavingAgent這個類裏的static字段,就會將JVM暴露給咱們的instrumentation保存下來。
private static final boolean AGENT_CLASS_PRESENT = ClassUtils.isPresent( "org.springframework.instrument.InstrumentationSavingAgent", InstrumentationLoadTimeWeaver.class.getClassLoader());
而後咱們這裏的addTransformer方法,就能夠將ClassFileTransformer設置到instrumentation裏面去:
@Override public void addTransformer(ClassFileTransformer transformer) { FilteringClassFileTransformer actualTransformer = new FilteringClassFileTransformer(transformer, this.classLoader); synchronized (this.transformers) { if (this.instrumentation == null) { throw new IllegalStateException( "Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation."); } // 這一句是核心! 將類字節碼轉換器,add到instrumentation字段。 this.instrumentation.addTransformer(actualTransformer); this.transformers.add(actualTransformer); } }
前面也說了,這個字段就是jvm暴露給咱們的,因此咱們對其進行操做,給它設置了ClassFileTransformer,以完成ltw的功能。
這一篇有點長,我感受寫了很久,但若是你們能細細閱讀並理解的話,我以爲目的也就達到了。可是,這個東西自己足夠複雜,因此,寫得確定有不那麼容易懂的地方,你們能夠問我。