继上一篇博客,我们继续来分析下面示例的 Spring 静态代理源码实现。
静态 AOP使用示例
加载时织入(Load -Time WEaving,LTW) 指的是在虚拟机载入字节码时动态织入 AspectJ切面,Spring 框架的值添加为 AspectJ LTW 在动态织入过程中提供了更加细粒度的控制,使用 Java(5+)的代理使用一个叫"Vanalla"的 AspectJ LTW,这需要在启动 JVM 的时候将某个 JVM 参数设置为开,这种 JVM 范围的设置在一些情况下或许不错,但通常情况下显得有些粗颗粒,而用 Spring 的 LTW 能让你的 per-ClassLoader 的基础上打开 LTW,这显然更加细粒度并且对单个 "JVM 多应用"的环境更具有意义(例如在一个典型的服务器环境中),另外在某些环境下,这能让你使用 LTW而不对应用服务器的启动脚本做任何改动,不然则需要添加-javaagent:path/to/aspectjweaver.jar 或者(以下将会提及) javaagent:path/to/spring-agent.jar,开发人员只需要简单的修改应用上下文的一个或几个文件就能使用 LTW ,则不需要那些管理者部署配置,比如启动脚本的系统管理员。说是这样说,但是本博客不考虑不使用-javaagent:path/to/aspectjweaver.jar的情况。
- 创建切面类和切点
PreGreetingAspect.java
@Aspect public class PreGreetingAspect { @Before("execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..))") public void beforeGreeting() { System.out.println("How are you"); } }
2.创建目标类
Waiter.java
public class Waiter{ public void greetTo(String name){ System.out.println("xxxxxxxxxxxxxx"); } }
3.准备Spring xml 文件
<?xml version="1.0" encoding="UTF-8"?> <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" xmlns:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:load-time-weaver></context:load-time-weaver> <bean class="com.spring_1_100.test_91_100.test97_ltw.Waiter"></bean> </beans>
4.添加 aop.xml,要在META-INF目标下添加。
aop.xml内容
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <aspects> <aspect name="com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect" ></aspect> </aspects> <weaver options="-showWeaveInfo -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler"> //告诉 Spring ,哪个包需要织入 <include within="com.spring_1_100.test_91_100.test97_ltw.*"></include> //是否需要对织入的类,织入前和织入后的类字节码保存起来 <dump within="*" beforeandafter="true" ></dump> </weaver> </aspectj>
dump参数表示对所有的目标类及切面类字节码,在修改之前和之后都 dump 到本地_ajdump目录。
添加 VM 参数
上面要注意的两点
- 可能有读者觉得 instrument.jar 包哪里来,只要你配置好 maven 环境后,直接到你的maven 仓库目录下寻找即可。
- 本次我使用 jdk1.7版本,如果使用 jdk1.8将有莫名其妙的错误。
环境准备好了,来测试一把。
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("spring_1_100/config_91_100/spring97_ltw.xml"); Waiter waiter = ctx.getBean(Waiter.class); waiter.greetTo("John"); }
结果输出:
结果在目标方法执行前打印出了 How are you
拥有多个转换器的 JVM 从加载类到最终生成对应的类字节码的过程。
使用 JVM启动参数注册转换器的问题
虽然可以通过-javaagent参数向 JVM 注册转换器,并对 JVM 中的类实施影响,但是转换器会对 JVM 所有的类都产生影响,这往往不是我们所期望的,如一个 Web 应用服务器上可能部署了多个 Web 应用。虽然不同的 Web 应用对应不同的 ClassLoader,但是转换器依旧会对不同的 ClassLoader 下所有的类产生影响,此外使用 JVM启动参数注册转换器,在实际操作上比较麻烦,给应用程序的部署带来了不便。
很多应用服务器都提供了拥有独立 Instrumentation 的 ClassLoader,我们称它们为组件 使能的类加载器(Instrumentable ClassLoader),组件能使 ClassLoader能将ClassFileTransformer 的作用范围限制在 ClassLoader 级别上,而非 JVM级别上。
我们在后面将看到 Spring 在这一方面做了不少的有意义的工作,它能够控制转换器的应用范围,让其仅对特定的 ClassLoader 产生影响,很多情况下无须配置 javaagent VM 参数。
使用 LTW 织入切面
Spring 的 LTW 仅支持AspectJ 定义切面,既可以是直接采用 AspectJ 语义定义的切面,也可以采用基于@AspectJ注解,通过 Java类定义的切面,Spring LTW 直接采用了 AspectJ LTW 相同的基础结构,即它利用类路径下的 META-INF/aop.xml 配置文件找到切面定义及切面所实施的候选目标类的信息,通过 LoadTimeWeaver在 ClassLoader 加载类文件时,将切面织入的目标类中,工作原理如下图:
Spring 利用特定的 Web 容器的 ClassLoader,通过 LoadTimeWeaver 将 Spring 提供的 ClassFileTransformer 注册到 ClassLoader 中,在类加载期,注册的 ClassFileTransformer 读取 AspectJ的配置文件,即类路径下的 META-INF/aop.xml文件,获取切面,对加载 VM 中的 Bean 类进行字节码的转换,织入切面,Spring 容器初始化 Bean 实例时,采用了 Bean 类就是己经被织入了切面的类,下面,我们来了解一下 Spring 的 LoadTimeWeaver。
Spring 的 LoadTimeWeaver
大多数的 Web 应用服务器(除 Tomcat外) 的 ClassLoader 都支持访问 Instrument,无须通过 javaagent 参数指定代理,拥有这种能力的 ClassLoader 称为"组件使能"(instrumentation-cable),通过"组件 使能"的功能,可以非常方便的访问到 ClassLoader 的 Instrument,Spring 利用了 Web 应用服务器加载这个特性,为它们分别提供了专门的 LoadTimeWeaver,以便向特定的 ClassLoader 注册 ClassFileTransformer,对类进行字节码的转换。实施切面织入功能。
Spring 的 org.springframework.instrument.classloading.LoadTimeWeaver 接口规定了类加载器织入器的高层协义,该接口中有3个方法 。
- void addTransformer(ClassFileTransformer transformer): 添加一个 ClassFileTransformer 到加载期织入器中。
- ClassLoader getInstrumentableClassLoader(): 我们知道 JVM 拥有 Instrumentaction 组件,但是这是 JVM级别的,Spring 对 ClassLoader 进行扩展,让它也具有 Instrumentation 组件,以便对 ClassLoader 中的类应用 ClassFileTransformer。
- ClassLoader getThrowawayClassLoader(): 返回一个丢弃的 ClassLoader,目的是使Instrumentation 的作用范围仅局限在本 ClassLoader 中,而不影响父ClassLoader。
Spring 为 LoadTimeWeaver 提供了多个实现。
- InstrumentationLoadTimeWeaver:该装载器织入器使用了-javaagent JVM 启动参数注册转换器,该类必需和 org.springframework.instrument.InstrumentactionSavingAgent 结合使用,InstrumentactionSavingAgent是代理类,它获取 JVM 的 instrumentaction后,以静态变量的方式保存这个引用,这样其他类就可以通过 getInstrumentation()方法从 InstrumentactionSavingAgent 中获取 JVM 的 Instrumentaction,InstrumentactionLoadTimeWeaver即利用 InstrumentactionSavingAgent 持有的 Instrumentation 引用完成添加转换器的操作。
- SimpleLoadTimeWeaver: 该装载器织入器能为当前的 ClassLoader创建一个相应的 SimpleInstrumentableClassLoader(简单组件使能的 ClassLoader 实现类),一般在测试或者 IDE 的环境下使用。
- 特定 Web服务器的织入器:JBossLoadTimeWeaver(在 JBoss AS 5.0以上版本使用) ,GlassFishLoadTimeWeaver(在 GlassFish 3.0以下版本使用),WebLogicLoadTimeWeaver(BEA WebLogic 10.0以上版本使用),OC4JLoadTimeWeaver(在 Oracle OC4J 10.1.3.1以上版本使用)。
- ReflectiveLoadTimeWeaver:有一些应用服务器不是组件使能 ClassLoader,或者虽然是组件使能,但是却无法获取应用服务器的类加载器实例,用户只能以 ClassLoader 类型获取这些类加载器的句柄,在这种情况下,Spring 没有办法实现一些特殊的方法,并由 ClassFileTransformer,可以扩展需要改造 ClassLoader 类,并实现以下的特殊方法达到目的。
1)public void addTransformer(java.lang.instrument.ClassFileTransformer):向 ClassLoader 中注册转换器
2)public ClassLoader getThrowawayClassLoader():返回需要丢弃的 ClassLoader ,Spring只需要在配置文件中添加一行配置就可以启动 LoadTimeWeaver
FilteringClassFileTransformer.java
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (!this.targetClassLoader.equals(loader)) { return null; } //targetTransformer是AspectJClassBypassingClassFileTransformer对象 return this.targetTransformer.transform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer); }
在调用 transform 方法,返回被织入类修改后的字节码。
AspectJClassBypassingClassFileTransformer.java
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //排除掉 org.aspectj和 org/aspectj 开头的包 if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) { return classfileBuffer; } //delegate是ClassPreProcessorAgentAdapter return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); }
ClassPreProcessorAgentAdapter.java
public class ClassPreProcessorAgentAdapter implements ClassFileTransformer { private static ClassPreProcessor s_preProcessor; public 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 + "'"); } //此时的s_preProcessor是 Aj return s_preProcessor.preProcess(className, bytes, loader, protectionDomain); } static { try { s_preProcessor = new Aj(); s_preProcessor.initialize(); } catch (Exception var1) { throw new ExceptionInInitializerError("could not initialize JSR163 preprocessor due to: " + var1.toString()); } } }
s_preProcessor在项目启动时会被初始化。
Aj.java
public byte[] preProcess(String className, byte[] bytes, ClassLoader loader, ProtectionDomain protectionDomain) { //deleLoader = "sun.reflect.DelegatingClassLoader"; //如果ClassLoader 为空或者 className 为空,或者 classLoader 的名字是sun.reflect.DelegatingClassLoader修改字节码操作 if (loader == null || className == null || loader.getClass().getName().equals(deleLoader)) { return bytes; } //打印相关日志 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) { WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext); if (weavingAdaptor == null) { if (trace.isTraceEnabled()) trace.exit("preProcess"); return bytes; } try { //设置保护域,保护域:类装载器将class文件load内存的时候会将它放置到一个保护域中 weavingAdaptor.setActiveProtectionDomain(protectionDomain); //对类字节码修改 byte[] newBytes = weavingAdaptor.weaveClass(className, bytes, false); //如果 aop.xml 配置文件中配置了需要 dump 字节码,这里就是 dump字节码操作 Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true); if (trace.isTraceEnabled()) trace.exit("preProcess", newBytes); return newBytes; } finally { //清空保护域 weavingAdaptor.setActiveProtectionDomain(null); } } } catch (Throwable th) { //dump 异常信息 Dump.dumpWithException(th); return bytes; } finally { CompilationAndWeavingContext.resetForThread(); } }
WeaverContainer.java
static class WeaverContainer { static WeavingAdaptor getWeaver(ClassLoader loader, IWeavingContext weavingContext) { ExplicitlyInitializedClassLoaderWeavingAdaptor adaptor = null; AdaptorKey adaptorKey = new AdaptorKey(loader); String loaderClassName = loader.getClass().getName(); synchronized (weavingAdaptors) { checkQ(); adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey); if (adaptor == null) { //以classLoader 为 key ,创建ExplicitlyInitializedClassLoaderWeavingAdaptor对象 ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor(); adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor); weavingAdaptors.put(adaptorKey, adaptor); } } // perform the initialization return adaptor.getWeavingAdaptor(loader, weavingContext); } }
ExplicitlyInitializedClassLoaderWeavingAdaptor.java
public ClassLoaderWeavingAdaptor getWeavingAdaptor(ClassLoader loader, IWeavingContext weavingContext) { initialize(loader, weavingContext); return weavingAdaptor; }
private void initialize(ClassLoader loader, IWeavingContext weavingContext) { if (!isInitialized) { isInitialized = true; weavingAdaptor.initialize(loader, weavingContext); } }
我们在adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor);时传入的是ClassLoaderWeavingAdaptor对象,因此在initialize方法中的weavingAdaptor是ClassLoaderWeavingAdaptor对象。我们进入ClassLoaderWeavingAdaptor的initialize()方法。
ClassLoaderWeavingAdaptor.java
public void initialize(final ClassLoader classLoader, IWeavingContext context) { if (initialized) { return; } boolean success = true; this.weavingContext = context; if (weavingContext == null) { //如果没有配置IWeavingContext,初始化weavingContext值为DefaultWeavingContext weavingContext = new DefaultWeavingContext(classLoader); } //创建消息处理器new WeavingAdaptorMessageHolder(new PrintWriter(System.err)) createMessageHandler(); //创建这个类SimpleGeneratedClassHandler的目的主要是dump类字节码文件 this.generatedClassHandler = new SimpleGeneratedClassHandler(classLoader); //如果 classpath*中没有配置 META-INF/aop.xml 或者 META-INF/aop.xml 中没有定义相关组件 List definitions = weavingContext.getDefinitions(classLoader, this); if (definitions.isEmpty()) { // enabled设置为false,flushMessages() disable(); if (trace.isTraceEnabled()) { trace.exit("initialize", definitions); } return; } bcelWorld = new LTWWorld(classLoader, weavingContext, getMessageHandler(), null); weaver = new BcelWeaver(bcelWorld); //注册所有的 definition success = registerDefinitions(weaver, classLoader, definitions); if (success) { //织入前准备,重写所有的切点,以效率最高的形式来执行切点,最后对切点进行排序 weaver.prepareForWeave(); enable(); success = weaveAndDefineConceteAspects(); } if (success) { enable(); } else { disable(); bcelWorld = null; weaver = null; } if (WeavedClassCache.isEnabled()) { initializeCache(classLoader, getAspectClassNames(definitions), generatedClassHandler, getMessageHandler()); } initialized = true; }
DefaultWeavingContext.java
public List<Definition> getDefinitions(final ClassLoader loader, final WeavingAdaptor adaptor) { if (trace.isTraceEnabled()) { trace.enter("getDefinitions", this, new Object[] { "goo", adaptor }); } //获取当前 classpath* 的 Definitions List<Definition> definitions = ((ClassLoaderWeavingAdaptor) adaptor).parseDefinitions(loader); if (trace.isTraceEnabled()) { trace.exit("getDefinitions", definitions); } return definitions; }
这里所说的 Definitions,就是我们所配置的一个个 aop.xml文件,一个 xml 文件对应一个 Definition
ClassLoaderWeavingAdaptor
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)); //如果当前ClassLoader等于 SystemClassLoader,从系统属性中获取 aj5.def=fileName 所配置的文件名 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())); } } //从当前环境中获取org.aspectj.weaver.loadtime.configuration,如果获取不到,使用默认的 //AOP_XML=META-INF/aop.xml;META-INF/aop-ajc.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(); //如果以 file:开头的路径 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 { //获取当前 Classpath* 下的所有 META-INF aop.xml 文件 Enumeration<URL> xmls = weavingContext.getResources(nextDefinition); 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; }
得到了 aop.xml文件,需要对 xml 文件中的元素进行解析,而 Spring使用DocumentParser对xml 文件进行解析。
DocumentParser.java
public static Definition parse(final URL url) throws Exception { if (CACHE && parsedFiles.containsKey(url.toString())) { return parsedFiles.get(url.toString()); } Definition def = null; if (LIGHTPARSER) { def = SimpleAOPParser.parse(url); } else { def = saxParsing(url); } if (CACHE && def.getAspectClassNames().size() > 0) { parsedFiles.put(url.toString(), def); } return def; }
DocumentParser.java
private static Definition saxParsing(URL url) throws SAXException, ParserConfigurationException, IOException { DocumentParser parser = new DocumentParser(); XMLReader xmlReader = getXMLReader(); xmlReader.setContentHandler(parser); xmlReader.setErrorHandler(parser); try { xmlReader.setFeature("http://xml.org/sax/features/validation", false); } catch (SAXException e) { } try { xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); } catch (SAXException e) { } try { xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); } catch (SAXException e) { } xmlReader.setEntityResolver(parser); InputStream in = url.openStream(); //Sax 解析 xmlReader.parse(new InputSource(in)); return parser.definition; }
当 sax解析 aop.xml 时,会回调下面方法,将aop.xml 元素封装成 Definition。
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (ASPECT_ELEMENT.equals(qName)) {//aspect String name = attributes.getValue(NAME_ATTRIBUTE);//name String scopePattern = replaceXmlAnd(attributes.getValue(SCOPE_ATTRIBUTE));//scope String requiredType = attributes.getValue(REQUIRES_ATTRIBUTE);//requires if (!isNull(name)) { definition.getAspectClassNames().add(name); if (scopePattern != null) { definition.addScopedAspect(name, scopePattern); } if (requiredType != null) { definition.setAspectRequires(name, requiredType); } } } else if (WEAVER_ELEMENT.equals(qName)) {//weaver String options = attributes.getValue(OPTIONS_ATTRIBUTE);//options if (!isNull(options)) { definition.appendWeaverOptions(options); } inWeaver = true; } else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) {//concrete-aspect String name = attributes.getValue(NAME_ATTRIBUTE);//name String extend = attributes.getValue(EXTEND_ATTRIBUTE);//extends String precedence = attributes.getValue(PRECEDENCE_ATTRIBUTE);//precedence String perclause = attributes.getValue(PERCLAUSE_ATTRIBUTE);//perclause if (!isNull(name)) { activeConcreteAspectDefinition = new Definition.ConcreteAspect(name, extend, precedence, perclause); definition.getConcreteAspects().add(activeConcreteAspectDefinition); } } else if (POINTCUT_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) {//pointcut String name = attributes.getValue(NAME_ATTRIBUTE);//name String expression = attributes.getValue(EXPRESSION_ATTRIBUTE);//expression if (!isNull(name) && !isNull(expression)) { activeConcreteAspectDefinition.pointcuts.add(new Definition.Pointcut(name, replaceXmlAnd(expression))); } } else if (DECLARE_ANNOTATION_ELEMENT.equals(qName) && activeConcreteAspectDefinition!=null) {//declare-annotation String methodSig = attributes.getValue("method"); String fieldSig = attributes.getValue("field"); String typePat = attributes.getValue("type"); String anno = attributes.getValue("annotation"); if (isNull(anno)) { throw new SAXException("Badly formed <declare-annotation> element, 'annotation' value is missing"); } if (isNull(methodSig) && isNull(fieldSig) && isNull(typePat)) { throw new SAXException("Badly formed <declare-annotation> element, need one of 'method'/'field'/'type' specified"); } if (!isNull(methodSig)) { activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Method, methodSig, anno)); } else if (!isNull(fieldSig)) { activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Field, fieldSig, anno)); } else if (!isNull(typePat)) { activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Type, typePat, anno)); } } else if (BEFORE_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) {//before String pointcut = attributes.getValue(POINTCUT_ELEMENT);//pointcut String adviceClass = attributes.getValue("invokeClass"); String adviceMethod = attributes.getValue("invokeMethod"); if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { activeConcreteAspectDefinition.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.Before, replaceXmlAnd(pointcut), adviceClass, adviceMethod)); } else { throw new SAXException("Badly formed <before> element"); } } else if (AFTER_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) {//after String pointcut = attributes.getValue("pointcut"); String adviceClass = attributes.getValue("invokeClass"); String adviceMethod = attributes.getValue("invokeMethod"); if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { activeConcreteAspectDefinition.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.After, replaceXmlAnd(pointcut), adviceClass, adviceMethod)); } else { throw new SAXException("Badly formed <after> element"); } } else if (AROUND_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) {//around String pointcut = attributes.getValue("pointcut"); String adviceClass = attributes.getValue("invokeClass"); String adviceMethod = attributes.getValue("invokeMethod"); if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { activeConcreteAspectDefinition.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.Around, replaceXmlAnd(pointcut), adviceClass, adviceMethod)); } else { throw new SAXException("Badly formed <before> element"); } } else if (ASPECTJ_ELEMENT.equals(qName)) {//aspectj if (inAspectJ) { throw new SAXException("Found nested <aspectj> element"); } inAspectJ = true; } else if (ASPECTS_ELEMENT.equals(qName)) {//aspects inAspects = true; } else if (INCLUDE_ELEMENT.equals(qName) && inWeaver) {//include String typePattern = getWithinAttribute(attributes); if (!isNull(typePattern)) { definition.getIncludePatterns().add(typePattern); } } else if (EXCLUDE_ELEMENT.equals(qName) && inWeaver) {//exclude String typePattern = getWithinAttribute(attributes); if (!isNull(typePattern)) { definition.getExcludePatterns().add(typePattern); } } else if (DUMP_ELEMENT.equals(qName) && inWeaver) {//dump String typePattern = getWithinAttribute(attributes); if (!isNull(typePattern)) { definition.getDumpPatterns().add(typePattern); } String beforeAndAfter = attributes.getValue(DUMP_BEFOREANDAFTER_ATTRIBUTE);//beforeandafter if (isTrue(beforeAndAfter)) { definition.setDumpBefore(true); } String perWeaverDumpDir = attributes.getValue(DUMP_PERCLASSLOADERDIR_ATTRIBUTE);//perclassloaderdumpdir if (isTrue(perWeaverDumpDir)) { definition.setCreateDumpDirPerClassloader(true); } } else if (EXCLUDE_ELEMENT.equals(qName) && inAspects) {//exclude String typePattern = getWithinAttribute(attributes); if (!isNull(typePattern)) { definition.getAspectExcludePatterns().add(typePattern); } } else if (INCLUDE_ELEMENT.equals(qName) && inAspects) {//include String typePattern = getWithinAttribute(attributes); if (!isNull(typePattern)) { definition.getAspectIncludePatterns().add(typePattern); } } else { throw new SAXException("Unknown element while parsing <aspectj> element: " + qName); } super.startElement(uri, localName, qName, attributes); }
通过上面的代码可以看到,如果没有手动配置org.aspectj.weaver.loadtime.configuration,Spring 会从当前系统环境中获取默认配置文件META-INF/aop.xml;META-INF/aop-ajc.xml;org/aspectj/aop.xml,再对文件逐一Sax 解析遍历,生成Definition保存到definitions 中。如下图所示:
初始化LTWWorld,看上去好像没有什么用,事实上在后面起到巨大作用,因为这个类保存了此次编织的 ClassLoader,在后面获取所有类的类型,字节码都依赖于这个类。
LTWWorld.java
public LTWWorld(ClassLoader loader, IWeavingContext weavingContext, IMessageHandler handler, ICrossReferenceHandler xrefHandler) { super(loader, handler, xrefHandler); this.weavingContext = weavingContext; classLoaderString = loader.toString(); classLoaderParentString = (loader.getParent() == null ? "<NullParent>" : loader.getParent().toString()); setBehaveInJava5Way(LangUtil.is15VMOrGreater()); annotationFinder = ReflectionWorld.makeAnnotationFinderIfAny(loader, this); }
BcelWeaver.java
public BcelWeaver(BcelWorld world) { super(); if (trace.isTraceEnabled()) { trace.enter("", this, world); } this.world = world; this.xcutSet = world.getCrosscuttingMembersSet(); if (trace.isTraceEnabled()) { trace.exit(""); } }
对所有的 Definition注册。
ClassLoaderWeavingAdaptor.java
private boolean registerDefinitions(final BcelWeaver weaver, final ClassLoader loader, List<Definition> definitions) { if (trace.isTraceEnabled()) { trace.enter("registerDefinitions", this, definitions); } boolean success = true; try { //注册aop.xml中所有的options参数 registerOptions(weaver, loader, definitions); //注册所有的exclude标签的内容 registerAspectExclude(weaver, loader, definitions);| //注册所有的include标签的内容 registerAspectInclude(weaver, loader, definitions); //注册所有的aspects标签的内容 success = registerAspects(weaver, loader, definitions); //根据exclude,include标签内容,创建快速匹配表达式 registerIncludeExclude(weaver, loader, definitions); //dump 字节码的配置 registerDump(weaver, loader, definitions); } catch (Exception ex) { trace.error("register definition failed", ex); success = false; warn("register definition failed", (ex instanceof AbortException) ? null : ex); } if (trace.isTraceEnabled()) { trace.exit("registerDefinitions", success); } return success; }
Options.java
private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) { StringBuffer allOptions = new StringBuffer(); for (Definition definition : definitions) { allOptions.append(definition.getWeaverOptions()).append(' '); } //获取到所有的weaver的options参数 Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader, getMessageHandler()); //将 options参数设置到 World 中 World world = weaver.getWorld(); setMessageHandler(weaverOption.messageHandler); world.setXlazyTjp(weaverOption.lazyTjp); world.setXHasMemberSupportEnabled(weaverOption.hasMember); world.setTiming(weaverOption.timers, true); world.setOptionalJoinpoints(weaverOption.optionalJoinpoints); world.setPinpointMode(weaverOption.pinpoint); weaver.setReweavableMode(weaverOption.notReWeavable); world.performExtraConfiguration(weaverOption.xSet); world.setXnoInline(weaverOption.noInline); //配置的当前 jdk版本是否小于1.5 world.setBehaveInJava5Way(LangUtil.is15VMOrGreater()); world.setAddSerialVerUID(weaverOption.addSerialVersionUID); // 加载classpath*下的XlintDefault.properties中的属性 bcelWorld.getLint().loadDefaultProperties(); /* Second overlay LTW defaults */ bcelWorld.getLint().adviceDidNotMatch.setKind(null); //options 参数中是否配置了-Xlintfile:,如果配置了,加载到属性中 if (weaverOption.lintFile != null) { InputStream resource = null; try { resource = loader.getResourceAsStream(weaverOption.lintFile); Exception failure = null; if (resource != null) { try { Properties properties = new Properties(); properties.load(resource); world.getLint().setFromProperties(properties); } catch (IOException e) { failure = e; } } if (failure != null || resource == null) { warn("Cannot access resource for -Xlintfile:" + weaverOption.lintFile, failure); } } finally { try { resource.close(); } catch (Throwable t) { } } } if (weaverOption.lint != null) { if (weaverOption.lint.equals("default")) { //加载XlintDefault.properties配置文件 bcelWorld.getLint().loadDefaultProperties(); } else { bcelWorld.getLint().setAll(weaverOption.lint); //如果options 的-Xlint:参数为ignore,设置bcelWorld的allLintIgnored为 true if (weaverOption.lint.equals("ignore")) { bcelWorld.setAllLintIgnored(); } } } }
public static WeaverOption parse(String options, ClassLoader laoder, IMessageHandler imh) { WeaverOption weaverOption = new WeaverOption(imh); if (LangUtil.isEmpty(options)) { return weaverOption; } //将当前 options 以" "分割 List flags = LangUtil.anySplit(options, " "); Collections.reverse(flags); //对所有option参数进行遍历,如果 option 参数中有-XmessageHandlerClass: 则取出value= //org.springframework.aop.aspectj.AspectJWeaverMessageHandler,设置为messageHandler值 for (Iterator iterator = flags.iterator(); iterator.hasNext();) { String arg = (String) iterator.next(); //OPTIONVALUED_messageHandler="-XmessageHandlerClass:" if (arg.startsWith(OPTIONVALUED_messageHandler)) { if (arg.length() > OPTIONVALUED_messageHandler.length()) { String handlerClass = arg.substring(OPTIONVALUED_messageHandler.length()).trim(); try { Class handler = Class.forName(handlerClass, false, laoder); weaverOption.messageHandler = ((IMessageHandler) handler.newInstance()); } catch (Throwable t) { weaverOption.messageHandler.handleMessage(new Message("Cannot instantiate message handler " + handlerClass, IMessage.ERROR, t, null)); } } } } //设置配置的其他参数 for (Iterator iterator = flags.iterator(); iterator.hasNext();) { String arg = (String) iterator.next(); if (arg.equals(OPTION_15)) {//-1.5 weaverOption.java5 = true; } else if (arg.equalsIgnoreCase(OPTION_lazyTjp)) {//-XlazyTjp weaverOption.lazyTjp = true; } else if (arg.equalsIgnoreCase(OPTION_noinline)) {//-Xnoinline weaverOption.noInline = true; } else if (arg.equalsIgnoreCase(OPTION_addSerialVersionUID)) {//-XaddSerialVersionUID weaverOption.addSerialVersionUID = true; } else if (arg.equalsIgnoreCase(OPTION_noWarn) || arg.equalsIgnoreCase(OPTION_noWarnNone)) {//-nowarn或-warn:none weaverOption.noWarn = true; } else if (arg.equalsIgnoreCase(OPTION_proceedOnError)) {//-proceedOnError weaverOption.proceedOnError = true; } else if (arg.equalsIgnoreCase(OPTION_reweavable)) {//-Xreweavable weaverOption.notReWeavable = false; } else if (arg.equalsIgnoreCase(OPTION_showWeaveInfo)) {//-showWeaveInfo weaverOption.showWeaveInfo = true; } else if (arg.equalsIgnoreCase(OPTION_hasMember)) {//-XhasMember weaverOption.hasMember = true; } else if (arg.startsWith(OPTIONVALUED_joinpoints)) {//-Xjoinpoints: if (arg.length() > OPTIONVALUED_joinpoints.length()) {//-Xjoinpoints: weaverOption.optionalJoinpoints = arg.substring(OPTIONVALUED_joinpoints.length()).trim(); } } else if (arg.equalsIgnoreCase(OPTION_verbose)) {//-verbose weaverOption.verbose = true; } else if (arg.equalsIgnoreCase(OPTION_debug)) {//-debug weaverOption.debug = true; } else if (arg.equalsIgnoreCase(OPTION_pinpoint)) {//-Xdev:pinpoint weaverOption.pinpoint = true; } else if (arg.startsWith(OPTIONVALUED_messageHandler)) {//-XmessageHandlerClass: // handled in first round } else if (arg.startsWith(OPTIONVALUED_Xlintfile)) {//-Xlintfile: if (arg.length() > OPTIONVALUED_Xlintfile.length()) {//-Xlintfile: weaverOption.lintFile = arg.substring(OPTIONVALUED_Xlintfile.length()).trim(); } } else if (arg.startsWith(OPTIONVALUED_Xlint)) {//-Xlint: if (arg.length() > OPTIONVALUED_Xlint.length()) {//-Xlint: weaverOption.lint = arg.substring(OPTIONVALUED_Xlint.length()).trim(); } } else if (arg.startsWith(OPTIONVALUED_Xset)) {//-Xset: if (arg.length() > OPTIONVALUED_Xlint.length()) {//-Xlint: weaverOption.xSet = arg.substring(OPTIONVALUED_Xset.length()).trim(); } } else if (arg.equalsIgnoreCase(OPTION_timers)) {//-timers weaverOption.timers = true; } else { weaverOption.messageHandler.handleMessage(new Message("Cannot configure weaver with option '" + arg + "': unknown option", IMessage.WARNING, null, null)); } } //-nowarn if (weaverOption.noWarn) { weaverOption.messageHandler.ignore(IMessage.WARNING); } //-verbose if (weaverOption.verbose) { weaverOption.messageHandler.dontIgnore(IMessage.INFO); } //-debug if (weaverOption.debug) { weaverOption.messageHandler.dontIgnore(IMessage.DEBUG); } //-showWeaveInfo if (weaverOption.showWeaveInfo) { weaverOption.messageHandler.dontIgnore(IMessage.WEAVEINFO); } return weaverOption; }
上面写了这么多的代码,其实就是将aop.xml配置的options参数封装成WeaverOption对象并返回。
ClassLoaderWeavingAdaptor.java
private boolean registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) { boolean success = true; //遍历所有的 Definition for (Definition definition : definitions) { for (String aspectClassName : definition.getAspectClassNames()) { if (acceptAspect(aspectClassName)) { //设置aspectClassName的require 类型 String requiredType = definition.getAspectRequires(aspectClassName); if (requiredType != null) { ((BcelWorld) weaver.getWorld()).addAspectRequires(aspectClassName, requiredType); } //设置aspectClassName的Scope类型 String definedScope = definition.getScopeForAspect(aspectClassName); if (definedScope != null) { ((BcelWorld) weaver.getWorld()).addScopedAspect(aspectClassName, definedScope); } //将aspectClassName生成的ResolvedType对象以crosscuttingMembers形式加入到CrosscuttingMembersSet中 weaver.addLibraryAspect(aspectClassName); //命名空间append if (namespace == null) { namespace = new StringBuffer(aspectClassName); } else { namespace = namespace.append(";").append(aspectClassName); } } else { lint("aspectExcludedByConfiguration", new String[] { aspectClassName, getClassLoaderName(loader) }); } } } //对concrete-aspect 标签的 Definition 进行遍历,并加入到 CrosscuttingMembersSet for (Definition definition : definitions) { for (Definition.ConcreteAspect concreteAspect : definition.getConcreteAspects()) { if (acceptAspect(concreteAspect.name)) { info("define aspect " + concreteAspect.name); ConcreteAspectCodeGen gen = new ConcreteAspectCodeGen(concreteAspect, weaver.getWorld()); if (!gen.validate()) { error("Concrete-aspect '" + concreteAspect.name + "' could not be registered"); success = false; break; } ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()), true); concreteAspects.add(gen); weaver.addLibraryAspect(concreteAspect.name); if (namespace == null) { namespace = new StringBuffer(concreteAspect.name); } else { namespace = namespace.append(";" + concreteAspect.name); } } } } if (!success) { warn("failure(s) registering aspects. Disabling weaver for class loader " + getClassLoaderName(loader)); } //如果 namespace为空,注册失败 else if (namespace == null) { success = false; info("no aspects registered. Disabling weaver for class loader " + getClassLoaderName(loader)); } return success; }
BcelWeaver.java
public ResolvedType addLibraryAspect(String aspectName) { UnresolvedType unresolvedT = UnresolvedType.forName(aspectName); unresolvedT.setNeedsModifiableDelegate(true); //这一行代码的实现也是非常的复杂,其中包括将 java 类转化成 java 字节码,并统一封装到 javaClass 中 ResolvedType type = world.resolve(unresolvedT, true); if (type.isMissing()) { //如果找不到此解析类型 String fixedName = aspectName; //字符串中是否包含. int hasDot = fixedName.lastIndexOf('.'); //下面这个代码的意思是这样的,如果一个类型 abc.def.fg没有找到匹配的 java 类型,则 //首先将 abc.def.fg替换成 abc.def$fg,再去找匹配的 java 类型,如果找不到,继续将最后一个.替换成$ // abc.def.fg将被替换成 abc$def$fg,再去换匹配的 java 类型,直到换到匹配的 java 类型为止 while (hasDot > 0) { //将字符串转换成字符数组 char[] fixedNameChars = fixedName.toCharArray(); //将字符串中最后一个点替换成$ fixedNameChars[hasDot] = '$'; fixedName = new String(fixedNameChars); hasDot = fixedName.lastIndexOf('.'); UnresolvedType ut = UnresolvedType.forName(fixedName); ut.setNeedsModifiableDelegate(true); type = world.resolve(ut, true); if (!type.isMissing()) { break; } } } //是否是 Aspect if (type.isAspect()) { WeaverStateInfo wsi = type.getWeaverState(); //好像是说 Spring 修改的一个 bug,获取到 未编织的java字节码,保存起来 if (wsi != null && wsi.isReweavable()) { BcelObjectType classType = getClassType(type.getName()); JavaClass wovenJavaClass = classType.getJavaClass(); byte[] bytes = wsi.getUnwovenClassFileData(wovenJavaClass.getBytes()); JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(), bytes); world.storeClass(unwovenJavaClass); classType.setJavaClass(unwovenJavaClass, true); } //添加或者替换 Aspect xcutSet.addOrReplaceAspect(type); if (type.getSuperclass().isAspect()) { //如果当前 Aspect 的父类也是 Aspect,也需要做添加或替换操作 addLibraryAspect(type.getSuperclass().getName()); } return type; } else { //如果不是Aspect,抛出异常 RuntimeException ex = new RuntimeException("Cannot register non aspect: " + type.getName() + " , " + aspectName); if (trace.isTraceEnabled()) { trace.exit("addLibraryAspect", ex); } throw ex; } }
CrosscuttingMembersSet
public boolean addOrReplaceAspect(ResolvedType aspectType, boolean inWeavingPhase) { //如果没有配置 //<aspects> // <aspect name="com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect" scope="com.spring_1_100.test_91_100.test97_ltw.*"></aspect> //</aspects> //如果没有配置上面的 scope 属性,这个 scope 属性值是一个表达式 // 或者 // <aspects> // <aspect name="com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect" requires="com.spring_1_100.test_91_100.test97_ltw$PreGreetingAspect"></aspect> //</aspects> //在requires属性中配置了com.spring_1_100.test_91_100.test97_ltw$PreGreetingAspect //当前类的类型也是com.spring_1_100.test_91_100.test97_ltw$PreGreetingAspect,但是在类加载中并没有 //com.spring_1_100.test_91_100.test97_ltw$PreGreetingAspect这种类型,则返回 false 。 if (!world.isAspectIncluded(aspectType) || world.hasUnsatisfiedDependency(aspectType)) { return false; } boolean change = false; CrosscuttingMembers xcut = members.get(aspectType); if (xcut == null) { members.put(aspectType, aspectType.collectCrosscuttingMembers(inWeavingPhase)); clearCaches(); change = true; } else { if (xcut.replaceWith(aspectType.collectCrosscuttingMembers(inWeavingPhase), inWeavingPhase)) { clearCaches(); change = true; } else { if (inWeavingPhase) { shadowMungers = null; } change = false; } } if (aspectType.isAbstract()) { boolean ancestorChange = addOrReplaceDescendantsOf(aspectType, inWeavingPhase); change = change || ancestorChange; } changedSinceLastReset = changedSinceLastReset || change; return change; }
public CrosscuttingMembers collectCrosscuttingMembers(boolean shouldConcretizeIfNeeded) { //初始化 CrosscuttingMembers crosscuttingMembers = new CrosscuttingMembers(this, shouldConcretizeIfNeeded); if (getPerClause() == null) { return crosscuttingMembers; } crosscuttingMembers.setPerClause(getPerClause()); //添加所有的切点表达式 crosscuttingMembers.addShadowMungers(collectShadowMungers()); //下面这几个,我也不知道是什么应用场景使用,先放在这里吧,将来有机会使用到,再来补了 crosscuttingMembers.addTypeMungers(getTypeMungers()); crosscuttingMembers.addDeclares(collectDeclares(!this.doesNotExposeShadowMungers())); crosscuttingMembers.addPrivilegedAccesses(getPrivilegedAccesses()); return crosscuttingMembers; }
CrosscuttingMembers.java
public void setPerClause(PerClause perClause) { //是否需要混合 if (shouldConcretizeIfNeeded) { this.perClause = perClause.concretize(inAspect); } else { this.perClause = perClause; } }
PerSingleton
public PerClause concretize(ResolvedType inAspect) { PerSingleton ret = new PerSingleton(); ret.copyLocationFrom(this); World world = inAspect.getWorld(); ret.inAspect = inAspect; //ATAJ:添加一个计数器以将AspectOf(..)添加到@AJ方面 if (inAspect.isAnnotationStyleAspect() && !inAspect.isAbstract()) { //如果是单例 if (getKind() == SINGLETON) { // pr149560 //将BcelPerClauseAspectAdder实例加入到 typeMungers中 inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().makePerClauseAspect(inAspect, getKind())); } else { inAspect.crosscuttingMembers.addLateTypeMunger(world.getWeavingSupport().makePerClauseAspect(inAspect, getKind())); } } // ATAJ 在线 around 支持,创建BcelAccessForInlineMunger加入到typeMungers中 if (inAspect.isAnnotationStyleAspect() && !inAspect.getWorld().isXnoInline()) { inAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().createAccessForInlineMunger(inAspect)); } return ret; }
当这个方法执行完成,this.perClause己经变成了PerSingleton对象了。
CrosscuttingMembers
public void addShadowMungers(Collection<ShadowMunger> c) { for (ShadowMunger munger : c) { addShadowMunger(munger); } }
CrosscuttingMembers
private void addShadowMunger(ShadowMunger m) { //当前切面类非抽象 if (inAspect.isAbstract()) { return; } //将得到的混合 munger 加入到shadowMungers中 addConcreteShadowMunger(m.concretize(inAspect, world, perClause)); }
混合 munger,这又是如何生成的呢?我们继续跟进代码。
BcelAdvice
public ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause) { if (!world.areAllLintIgnored()) { suppressLintWarnings(world); } //获取混合 ShadowMuger ShadowMunger ret = super.concretize(fromType, world, clause); if (!world.areAllLintIgnored()) { clearLintSuppressions(world, this.suppressedLintKinds); } IfFinder ifinder = new IfFinder(); //当前切点表达式中是否有 if ret.getPointcut().accept(ifinder, null); boolean hasGuardTest = ifinder.hasIf && getKind() != AdviceKind.Around; boolean isAround = getKind() == AdviceKind.Around; if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { if (!isAround && !hasGuardTest && world.getLint().noGuardForLazyTjp.isEnabled()) { world.getLint().noGuardForLazyTjp.signal("", getSourceLocation()); } } return ret; }
Advice
public ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause) { //在本例中,我们以为关键代码是下面这一句,但是不是,下面方法只是做了一些变量赋值和对象考备操作 Pointcut p = pointcut.concretize(fromType, getDeclaringType(), signature.getArity(), this); if (clause != null) { Pointcut oldP = p; //真正的混合 Point 代码,是将 perClause 和 pointcut 混合,将 left设置为 perClause,pointcut设置为right p = new AndPointcut(clause, p); p.copyLocationFrom(oldP); p.state = Pointcut.CONCRETE; //复制旧的m_ignoreUnboundBindingForNames p.m_ignoreUnboundBindingForNames = oldP.m_ignoreUnboundBindingForNames; } //创建新的BcelAdvice对象,绑定参数类型,并返回 Advice munger = world.getWeavingSupport().createAdviceMunger(attribute, p, signature, fromType); munger.bindingParameterTypes = bindingParameterTypes; munger.setDeclaringType(getDeclaringType()); return munger; }
ResolvedType.java
private final List<ShadowMunger> collectShadowMungers() { if (!this.isAspect() || this.isAbstract() || this.doesNotExposeShadowMungers()) { return Collections.emptyList(); } List<ShadowMunger> acc = new ArrayList<ShadowMunger>(); //己经查找过的祖先业,不再进行查找 final Iterators.Filter<ResolvedType> dupFilter = Iterators.dupFilter(); Iterators.Getter<ResolvedType, ResolvedType> typeGetter = new Iterators.Getter<ResolvedType, ResolvedType>() { public Iterator<ResolvedType> get(ResolvedType o) { //获取当前类的所有的父类及接口 return dupFilter.filter((o).getDirectSupertypes()); } }; Iterator<ResolvedType> typeIterator = Iterators.recur(this, typeGetter); //上面主要是获取当前类及父类及父接口的所有切点表达式,但是可能做了一些优化操作,如 // A 继承 B 实现 C 接口,B 也实现 C 接口,如果 A在查找过程中己经查找了 C 接口,在查找 B的切面表达式时, //发现也实现了 C接口,因为在查找 A 类时,己经查找过 C 接口,则不再查找 while (typeIterator.hasNext()) { ResolvedType ty = typeIterator.next(); acc.addAll(ty.getDeclaredShadowMungers()); } return acc; }
ResolvedType
public List<ShadowMunger> getDeclaredAdvice() { List<ShadowMunger> l = new ArrayList<ShadowMunger>(); //获取当前类的所有方法 ResolvedMember[] methods = getDeclaredMethods(); if (isParameterizedType()) { //如果是参数化类型 methods = getGenericType().getDeclaredMethods(); } Map<String, UnresolvedType> typeVariableMap = getAjMemberParameterizationMap(); for (int i = 0, len = methods.length; i < len; i++) { ShadowMunger munger = methods[i].getAssociatedShadowMunger(); if (munger != null) { //当前方法是否是参数化类型 if (ajMembersNeedParameterization()) { // munger.setPointcut(munger.getPointcut().parameterizeWith( // typeVariableMap)); munger = munger.parameterizeWith(this, typeVariableMap); if (munger instanceof Advice) { Advice advice = (Advice) munger; // update to use the parameterized signature... UnresolvedType[] ptypes = methods[i].getGenericParameterTypes(); UnresolvedType[] newPTypes = new UnresolvedType[ptypes.length]; for (int j = 0; j < ptypes.length; j++) { if (ptypes[j] instanceof TypeVariableReferenceType) { TypeVariableReferenceType tvrt = (TypeVariableReferenceType) ptypes[j]; if (typeVariableMap.containsKey(tvrt.getTypeVariable().getName())) { newPTypes[j] = typeVariableMap.get(tvrt.getTypeVariable().getName()); } else { newPTypes[j] = ptypes[j]; } } else { newPTypes[j] = ptypes[j]; } } //advice 绑定新的参数类型 advice.setBindingParameterTypes(newPTypes); } } //设置ShadowMunger的DeclaringType为当前切面类 munger.setDeclaringType(this); l.add(munger); } } return l; }
ReferenceType.java
public ResolvedMember[] getDeclaredMethods() { if (parameterizedMethods != null) { return parameterizedMethods; } //如果当前为是参数化类型或者原始类型 if (isParameterizedType() || isRawType()) { //获取到所有方法 ResolvedMember[] delegateMethods = getDelegate().getDeclaredMethods(); //获取到参数类型 UnresolvedType[] parameters = getTypesForMemberParameterization(); parameterizedMethods = new ResolvedMember[delegateMethods.length]; for (int i = 0; i < delegateMethods.length; i++) { //方法参数,参数类型绑定 parameterizedMethods[i] = delegateMethods[i].parameterizedWith(parameters, this, isParameterizedType()); } return parameterizedMethods; } else { //获取切面类所有方法 return getDelegate().getDeclaredMethods(); } }
public ResolvedMember[] getDeclaredMethods() { ensureGenericSignatureUnpacked(); if (methods == null) { Method[] ms = javaClass.getMethods(); methods = new ResolvedMember[ms.length]; for (int i = ms.length - 1; i >= 0; i--) { //将当前方法构建成BcelMethod对象 methods[i] = new BcelMethod(this, ms[i]); } } return methods; }
BcelMethod.java
BcelMethod(BcelObjectType declaringType, Method method) { //kind :设置方法类型CONSTRUCTOR,或者STATIC_INITIALIZATION或METHOD类型 //declaringType :方法所在类 //modifiers :方法访问标志,public 或 private //name :方法名 //erasedSignature : 方法签名 ()V //returnType:方法返回值类型 //parameterTypes:方法参数类型 super(method.getName().equals("<init>") ? CONSTRUCTOR : (method.getName().equals("<clinit>") ? STATIC_INITIALIZATION : METHOD), declaringType.getResolvedTypeX(), declaringType.isInterface() ? method.getModifiers() | Modifier.INTERFACE : method.getModifiers(), method.getName(), method.getSignature()); this.method = method; sourceContext = declaringType.getResolvedTypeX().getSourceContext(); bcelObjectType = declaringType; //方法所在类 unpackJavaAttributes(); unpackAjAttributes(bcelObjectType.getWorld()); }
BcelMethod.java
private void unpackAjAttributes(World world) { associatedShadowMunger = null; ResolvedType resolvedDeclaringType = getDeclaringType().resolve(world); WeaverVersionInfo wvinfo = bcelObjectType.getWeaverVersionAttribute(); //从方法属性表查找到类型为Unknown的属性 List<AjAttribute> as = Utility.readAjAttributes(resolvedDeclaringType.getClassName(), method.getAttributes(), resolvedDeclaringType.getSourceContext(), world, wvinfo, new BcelConstantPoolReader(method.getConstantPool())); //处理属性 processAttributes(world, as); as = AtAjAttributes.readAj5MethodAttributes(method, this, resolvedDeclaringType, preResolvedPointcut, resolvedDeclaringType.getSourceContext(), world.getMessageHandler()); processAttributes(world, as); }
AtAjAttributes.java
public static List<AjAttribute> readAj5MethodAttributes(Method method, BcelMethod bMethod, ResolvedType type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) { //如果方法名以ajc$开头,表示该方法己经被处理了 if (method.getName().startsWith(NameMangler.PREFIX)) { return Collections.emptyList(); } //以方法,方法所在类,以及消息处理器构建AjAttributeMethodStruct对象 AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, bMethod, type, context, msgHandler); Attribute[] attributes = method.getAttributes(); boolean hasAtAspectJAnnotation = false; boolean hasAtAspectJAnnotationMustReturnVoid = false; for (int i = 0; i < attributes.length; i++) { Attribute attribute = attributes[i]; try { if (acceptAttribute(attribute)) { RuntimeAnnos rvs = (RuntimeAnnos) attribute; //@Before 注解方法处理 hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleBeforeAnnotation(rvs, struct, preResolvedPointcut); //@After注解方法处理 hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterAnnotation(rvs, struct, preResolvedPointcut); //@AfterReturning 注解方法处理 hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut, bMethod); //AfterThrowing注解方法处理 hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid || handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut, bMethod); //@Around 注解方法处理 hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(rvs, struct, preResolvedPointcut); break; } } catch (ReturningFormalNotDeclaredInAdviceSignatureException e) { msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE, e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation())); } catch (ThrownFormalNotDeclaredInAdviceSignatureException e) { msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.THROWN_FORMAL_NOT_DECLARED_IN_ADVICE, e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation())); } } //下面的代码主要是对消息进行处理了 hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid; if (hasAtAspectJAnnotation && !type.isAspect()) { msgHandler.handleMessage(new Message("Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'", IMessage.WARNING, null, type.getSourceLocation())); } if (hasAtAspectJAnnotation && !struct.method.isPublic()) { msgHandler.handleMessage(new Message("Found @AspectJ annotation on a non public advice '" + methodToString(struct.method) + "'", IMessage.ERROR, null, type.getSourceLocation())); } if (hasAtAspectJAnnotation && struct.method.isStatic()) { msgHandler.handleMessage(MessageUtil.error("Advice cannot be declared static '" + methodToString(struct.method) + "'", type.getSourceLocation())); } if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) { msgHandler.handleMessage(new Message("Found @AspectJ annotation on a non around advice not returning void '" + methodToString(struct.method) + "'", IMessage.ERROR, null, type.getSourceLocation())); } return struct.ajAttributes; }
因为对于方法注解处理大同小异,这里只挑选handleBeforeAnnotation()方法进行解析。
AtAjAttributes.java
private static boolean handleBeforeAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { //方法是否配置了Lorg/aspectj/lang/annotation/Before;注解 AnnotationGen before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION); if (before != null) { //获取@Before()注解的 value 值 NameValuePair beforeAdvice = getAnnotationElement(before, VALUE); if (beforeAdvice != null) { //获取argNames值 String argumentNames = getArgNamesValue(before); if (argumentNames != null) { struct.unparsedArgumentNames = argumentNames; } FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; try { bindings = extractBindings(struct); } catch (UnreadableDebugInfoException unreadableDebugInfoException) { return false; } IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); //joinpoint, staticJoinpoint binding int extraArgument = extractExtraArgument(struct.method); Pointcut pc = null; if (preResolvedPointcut != null) { pc = preResolvedPointcut.getPointcut(); } else { pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct, false); if (pc == null) { return false;// parse error } //这个方法,也很重要,如 // @Pointcut("execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..))") // public void test() { // } // @Before("test()") // public void beforeTest() { // System.out.println("beforeTest"); // } // 我们知道@Before 的切面表达式是execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..)) ,但是 //在源码中配置的是 test() ,在下面方法中将找到test()对应的切面表达式execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..)) pc = pc.resolve(binding); } //将JoinPoint,ProceedingJoinPoint,JoinPoint$StaticPart,JoinPoint$EnclosingStaticPart,AroundClosure类型的参数名加入到m_ignoreUnboundBindingForNames setIgnoreUnboundBindingNames(pc, bindings); ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); //封装AjAttribute.AdviceAttribute对象返回,AdviceAttribute中包含切点类型,切点表达式类型,非JoinPoint等参数类型 struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Before, pc, extraArgument, sl.getOffset(), sl .getOffset() + 1, struct.context)); return true; } } return false; }
AtAjAttributes.java
private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct) throws UnreadableDebugInfoException { Method method = struct.method; String[] argumentNames = struct.getArgumentNames(); //如果方法参数名的长度和方法参数类型个数不一致,抛出异常 if (argumentNames.length != method.getArgumentTypes().length) { reportError( "Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)", struct); throw new UnreadableDebugInfoException(); } List<FormalBinding> bindings = new ArrayList<FormalBinding>(); for (int i = 0; i < argumentNames.length; i++) { String argumentName = argumentNames[i]; UnresolvedType argumentType = UnresolvedType.forSignature(method.getArgumentTypes()[i].getSignature()); //如果参数类型是 //org.aspectj.lang.JoinPoint; //org.aspectj.lang.ProceedingJoinPoint; //org.aspectj.lang.JoinPoint$StaticPart; //org.aspectj.lang.JoinPoint$EnclosingStaticPart; //org.aspectj.runtime.internal.AroundClosure; 类型,构建FormalBinding.ImplicitFormalBinding对象,非上面的这些类型构建FormalBinding,保存到bindings中 if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType) || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType) || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType) || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType) || AjcMemberMaker.AROUND_CLOSURE_TYPE .equals(argumentType))) { bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i)); } else { bindings.add(new FormalBinding(argumentType, argumentName, i)); } } return bindings.toArray(new FormalBinding[] {}); }
AtAjAttributes.java
private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct struct, boolean allowIf) { try { PatternParser parser = new PatternParser(pointcutString, struct.context); //之前花了一篇博客 //Spring源码深度解析(郝佳)-学习-源码解析-aop切面表达式解析(二) //来解析下面的这一行代码,这里就不再赘述了,这一行代码主要是将 //execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..))解析成相应的切点 Pointcut pointcut = parser.parsePointcut(); //较验表达式是否解析线束 parser.checkEof(); //如果表达式类型是SynchronizationLock或SynchronizationUnlock ,设置synchronizationDesignatorEncountered = true; pointcut.check(null, struct.enclosingType.getWorld()); //如果不允许表达式中有 if,但是表达式中出现了 if,抛出异常 if (!allowIf && pointcutString.indexOf("if()") >= 0 && hasIf(pointcut)) { reportError("if() pointcut is not allowed at this pointcut location '" + pointcutString + "'", struct); return null; } pointcut.setLocation(struct.context, -1, -1);// FIXME -1,-1 is not return pointcut; } catch (ParserException e) { reportError("Invalid pointcut '" + pointcutString + "': " + e.toString() + (e.getLocation() == null ? "" : " at position " + e.getLocation().getStart()), struct); return null; } }
经过上面的一系列方法属性处理,我们终于得到了List对象,下面将对AjAttribute属性做处理了。
BcelMethod.java
private void processAttributes(World world, List<AjAttribute> as) { for (AjAttribute attr : as) { if (attr instanceof AjAttribute.MethodDeclarationLineNumberAttribute) { declarationLineNumber = (AjAttribute.MethodDeclarationLineNumberAttribute) attr; } else if (attr instanceof AjAttribute.AdviceAttribute) { associatedShadowMunger = ((AjAttribute.AdviceAttribute) attr).reify(this, world, (ResolvedType) getDeclaringType()); } else if (attr instanceof AjAttribute.AjSynthetic) { bitflags |= IS_AJ_SYNTHETIC; } else if (attr instanceof AjAttribute.EffectiveSignatureAttribute) { effectiveSignature = (AjAttribute.EffectiveSignatureAttribute) attr; } else if (attr instanceof AjAttribute.PointcutDeclarationAttribute) { preResolvedPointcut = ((AjAttribute.PointcutDeclarationAttribute) attr).reify(); } else { throw new BCException("weird method attribute " + attr); } } }
AdviceAttribute.java
public Advice reify(Member signature, World world, ResolvedType concreteAspect) { return world.getWeavingSupport().createAdviceMunger(this, pointcut, signature, concreteAspect); }
BcelWeavingSupport.java
public Advice createAdviceMunger(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member signature, ResolvedType concreteAspect) { return new BcelAdvice(attribute, pointcut, signature, concreteAspect); }
到这里,我们终于得到了BcelAdvice对象。下面的方法主要是快速匹配 include和exlude表达式
ClassLoaderWeavingAdaptor.java
private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) { String fastMatchInfo = null; for (Definition definition : definitions) { //对所有的 Definitions中的include标签配置的表达式进行遍历 for (Iterator<String> iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) { hasIncludes = true; String include = iterator1.next(); //charsss..*,cha.rss..* 表达式,会去除末尾的..*,取出charsss或cha.rss作为表达式开头,所有以charsss或cha.rss开头的表达式将被加入到m_includeStartsWith中 //*..*,*,charsss.*,将不会被加入到m_includeStartsWith中 fastMatchInfo = looksLikeStartsWith(include); if (fastMatchInfo != null) { m_includeStartsWith.add(fastMatchInfo); // 如果只有一个*,则includeStar=true } else if (include.equals("*")) { includeStar = true; //如果没有*,则精确匹配 } else if ((fastMatchInfo = looksLikeExactName(include)) != null) { includeExactName.add(fastMatchInfo); } else { //只有调用 new PatternParser(include)来获取类型匹配了 TypePattern includePattern = new PatternParser(include).parseTypePattern(); includeTypePattern.add(includePattern); } } for (Iterator<String> iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) { hasExcludes = true; String exclude = iterator1.next(); fastMatchInfo = looksLikeStartsWith(exclude); if (fastMatchInfo != null) { //charsss..*,cha.rss..* 表达式,会去除末尾的..*,取出charsss或cha.rss作为表达式开头,所有以charsss或cha.rss开头的表达式将被加入到excludeStartsWith中 //*..*,*,charsss.*,将不会被加入到excludeStartsWith中 excludeStartsWith.add(fastMatchInfo); } else if ((fastMatchInfo = looksLikeStarDotDotStarExclude(exclude)) != null) { //*..*XXXX*:如果是这种表达式,将返回 XXXX,会被加入到excludeStarDotDotStar中 //如果是*..*XX*X*,或者*..*X.XX*,将不会被加入到excludeStarDotDotStar //如果是*..*XX$X*,将返回 XX.X,加入到excludeStarDotDotStar,开启 CGLIB 匹配模式 excludeStarDotDotStar.add(fastMatchInfo); } else if ((fastMatchInfo = looksLikeExactName(exclude)) != null) { //如果字符串中不包含空格,@,+ 以及* ,则将表达式$替换成.加入到excludeExactName中 //abc@d ,不会被加入 //ab c ,不会被加入 //ab+d ,不会被加入 //ab@d+f ,不会被加入 //ab$d ,会被替换成 ab.d 加入到excludeExactName中 excludeExactName.add(exclude); } else if ((fastMatchInfo = looksLikeEndsWith(exclude)) != null) { //对于开头是*Exception截取出Exception加入到excludeEndsWith中,截取第一位后面的字符串中包含空格,@,+ ,*,. ,不会被加入到excludeEndsWith中 //**Exception,不会被加入 //*.abc,不会被加入 //*@abc 不会被加入 excludeEndsWith.add(fastMatchInfo); } else if (exclude .equals("org.codehaus.groovy..* && !org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController*")) { excludeSpecial.add(new String[] { "org.codehaus.groovy.", "org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController" }); } else { //只能用 new PatternParser(exclude)获取类型匹配器 TypePattern excludePattern = new PatternParser(exclude).parseTypePattern(); excludeTypePattern.add(excludePattern); } } } }
ClassLoaderWeavingAdaptor.java
private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) { for (Definition definition : definitions) { for (Iterator<String> iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) { //对 dump 目标表达式设置 String dump = iterator1.next(); TypePattern pattern = new PatternParser(dump).parseTypePattern(); m_dumpTypePattern.add(pattern); } //是否保存字节码没有改变时类文件 if (definition.shouldDumpBefore()) { m_dumpBefore = true; } //dump下来的文件,是否根据不同的 claddLoader 生成不同目录 if (definition.createDumpDirPerClassloader()) { dumpDirPerClassloader = true; } } }
对于registerDump方法,主要对 dump 文件范围和字节码文件在没有改变之前,是否 dump,以及是否根据类加载器的不同dump 到不同的目录中。
WeavingAdaptor.java
public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IOException { if (trace == null) { System.err .println("AspectJ Weaver cannot continue to weave, static state has been cleared. Are you under Tomcat? In order to weave '" + name + "' during shutdown, 'org.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false' must be set (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=231945)."); return bytes; } if (weaverRunning.get()) { return bytes; } try { weaverRunning.set(true); //如果初始化weave失败,不做增强处理 if (!enabled) { return bytes; } try { delegateForCurrentClass = null; name = name.replace('/', '.'); //如果目标类名以org.aspectj.,sun.reflect. 直接过虑,对于 java. 和javax. 开头的名字,就要看配置文件中是否配置了 if (couldWeave(name, bytes)) { if (accept(name, bytes)) { CachedClassReference cacheKey = null; byte[] original_bytes = bytes; //从缓存中获取字节码,获取到了,直接返回 if (cache != null && !mustWeave) { cacheKey = cache.createCacheKey(name, bytes); CachedClassEntry entry = cache.get(cacheKey); if (entry != null) { if (entry.isIgnored()) { return bytes; } return entry.getBytes(); } } //开始编织字节码 bytes = getWovenBytes(name, bytes); if (cacheKey != null) { if (Arrays.equals(original_bytes, bytes)) { cache.ignore(cacheKey); } else { cache.put(cacheKey, bytes); } } } } } finally { delegateForCurrentClass = null; } return bytes; } finally { weaverRunning.set(false); } }
ClassLoaderWeavingAdaptor.java
protected boolean accept(String className, byte[] bytes) { if (!hasExcludes && !hasIncludes) { //只要配置文件中配置了 include 或者 exclude将不会进入下面判断 return true; } String fastClassName = className.replace('/', '.'); //charsss..*,cha.rss..* 表达式,会去除末尾的..*,取出charsss或cha.rss作为表达式开头,所有以charsss或cha.rss开头的表达式将被加入到excludeStartsWith中 //*..*,*,charsss.*,将不会被加入到excludeStartsWith中 //因此如果配置了charsss..*,cha.rss..* ,则看目标类是否以charsss,或者cha.rss开头 for (String excludeStartsWithString : excludeStartsWith) { if (fastClassName.startsWith(excludeStartsWithString)) { return false; } } if (!excludeStarDotDotStar.isEmpty()) { //*..*XXXX*:如果是这种表达式,将返回 XXXX,会被加入到excludeStarDotDotStar中 //如果是*..*XX*X*,或者*..*X.XX*,将不会被加入到excludeStarDotDotStar //如果是*..*XX$X*,将返回 XX.X,加入到excludeStarDotDotStar,开启 CGLIB 匹配模式 //如 目标类名是 com.ab.def ,而namePiece是 de,取出最后一个.后面的字符串def 与之匹配,def 被 de匹配到,返回 false for (String namePiece : excludeStarDotDotStar) { int index = fastClassName.lastIndexOf('.'); if (fastClassName.indexOf(namePiece, index + 1) != -1) { return false; } } } //这种情况,是对类名中有$的处理,也就是对代理类处理 fastClassName = fastClassName.replace('$', '.'); if (!excludeEndsWith.isEmpty()) { //对于开头是*Exception截取出Exception加入到excludeEndsWith中,截取第一位后面的字符串中包含空格,@,+ ,*,. ,不会被加入到excludeEndsWith中 //**Exception,不会被加入 //*.abc,不会被加入 //*@abc 不会被加入 //如果类名以fastClassName结尾,将返回 false for (String lastPiece : excludeEndsWith) { if (fastClassName.endsWith(lastPiece)) { return false; } } } if (!excludeExactName.isEmpty()) { //如果字符串中不包含空格,@,+ 以及* ,则将表达式$替换成.加入到excludeExactName中 //abc@d ,不会被加入 //ab c ,不会被加入 //ab+d ,不会被加入 //ab@d+f ,不会被加入 //ab$d ,会被替换成 ab.d 加入到excludeExactName中 //如果是精确匹配类名,只要类名被匹配到,将返回 false for (String name : excludeExactName) { if (fastClassName.equals(name)) { return false; } } } if (!excludeSpecial.isEmpty()) { //如果是"org.codehaus.groovy.","org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController",则 //那么方法名以org.codehaus.groovy开头,但是又不是org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController开头,将返回 false for (String[] entry : excludeSpecial) { String excludeThese = entry[0]; String exceptThese = entry[1]; if (fastClassName.startsWith(excludeThese) && !fastClassName.startsWith(exceptThese)) { return false; } } } boolean didSomeIncludeMatching = false; if (excludeTypePattern.isEmpty()) { //如果 include 配置的是* if (includeStar) { return true; } if (!includeExactName.isEmpty()) { didSomeIncludeMatching = true; //如果精确匹配名称不为空 ,且目标类名和配置名完全相等,返回 true for (String exactname : includeExactName) { if (fastClassName.equals(exactname)) { return true; } } } boolean fastAccept = false; for (int i = 0; i < m_includeStartsWith.size(); i++) { didSomeIncludeMatching = true; //如果目标类名以配置的 m_includeStartsWith名开头,返回 true fastAccept = fastClassName.startsWith(m_includeStartsWith.get(i)); if (fastAccept) { return true; } } if (includeTypePattern.isEmpty()) { return !didSomeIncludeMatching; } } boolean accept; try { //确保代理类被初始化,读取目标类的字节码结构 ensureDelegateInitialized(className, bytes); //获取目标类信息 ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX(); for (TypePattern typePattern : excludeTypePattern) { //对所有排除进行切点匹配,在之前的博客中,我们花了一篇博客来讲解,这里就不多说了 if (typePattern.matchesStatically(classInfo)) { return false; } } if (includeStar) { return true; } if (!includeExactName.isEmpty()) { didSomeIncludeMatching = true; for (String exactname : includeExactName) { if (fastClassName.equals(exactname)) { return true; } } } for (int i = 0; i < m_includeStartsWith.size(); i++) { didSomeIncludeMatching = true; boolean fastaccept = fastClassName.startsWith(m_includeStartsWith.get(i)); if (fastaccept) { return true; } } accept = !didSomeIncludeMatching; for (TypePattern typePattern : includeTypePattern) { //对所有切点表达式匹配成功的,直接返回 true accept = typePattern.matchesStatically(classInfo); if (accept) { break; } } } finally { this.bcelWorld.demote(); } return accept; }
WeavingAdaptor.java
private byte[] getWovenBytes(String name, byte[] bytes) throws IOException { WeavingClassFileProvider wcp = new WeavingClassFileProvider(name, bytes); //开始编织 weaver.weave(wcp); return wcp.getBytes(); }
BcelWeaver.java
public Collection<String> weave(IClassFileProvider input) throws IOException { //创建当前线程下的 token ContextToken weaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING, ""); Collection<String> wovenClassNames = new ArrayList<String>(); IWeaveRequestor requestor = input.getRequestor(); if (world.getModel() != null && world.isMinimalModel()) { candidatesForRemoval = new HashSet<IProgramElement>(); } if (world.getModel() != null && !isBatchWeave) { AsmManager manager = world.getModelAsAsmManager(); for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); manager.removeRelationshipsTargettingThisType(classFile.getClassName()); } } //仔细检查类型,并确保在编织之前修复所有“损坏”的对象 for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); String className = classFile.getClassName(); ResolvedType theType = world.resolve(className); if (theType != null) { theType.ensureConsistent(); } } //对于特殊情况处理,我也不知道是什么情况 if (input.isApplyAtAspectJMungersOnly()) { ContextToken atAspectJMungersOnly = CompilationAndWeavingContext.enteringPhase( CompilationAndWeavingContext.PROCESSING_ATASPECTJTYPE_MUNGERS_ONLY, ""); requestor.weavingAspects(); CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); String className = classFile.getClassName(); ResolvedType theType = world.resolve(className); if (theType.isAnnotationStyleAspect()) { BcelObjectType classType = BcelWorld.getBcelObjectType(theType); if (classType == null) { throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); } LazyClassGen clazz = classType.getLazyClassGen(); BcelPerClauseAspectAdder selfMunger = new BcelPerClauseAspectAdder(theType, theType.getPerClause().getKind()); selfMunger.forceMunge(clazz, true); classType.finishedWith(); UnwovenClassFile[] newClasses = getClassFilesFor(clazz); for (int news = 0; news < newClasses.length; news++) { requestor.acceptResult(newClasses[news]); } wovenClassNames.add(classFile.getClassName()); } } requestor.weaveCompleted(); CompilationAndWeavingContext.leavingPhase(atAspectJMungersOnly); return wovenClassNames; } requestor.processingReweavableState(); ContextToken reweaveToken = CompilationAndWeavingContext.enteringPhase( CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, ""); prepareToProcessReweavableState(); //我们在重新编织之前清理所有的状态 for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); String className = classFile.getClassName(); BcelObjectType classType = getClassType(className); if (classType != null) { ContextToken tok = CompilationAndWeavingContext.enteringPhase( CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, className); processReweavableStateIfPresent(className, classType); CompilationAndWeavingContext.leavingPhase(tok); } } CompilationAndWeavingContext.leavingPhase(reweaveToken); ContextToken typeMungingToken = CompilationAndWeavingContext.enteringPhase( CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, ""); requestor.addingTypeMungers(); //我们将类型的Mungers分为两组,首先是更改类型层次结构的Munger,然后是“普通” 类型的Munger。 //以可预测的顺序(而不是遇到的顺序)处理类型。 //对于类A,顺序是A的超类,然后是A的超接口(并且此机制是递归应用的) List<String> typesToProcess = new ArrayList<String>(); for (Iterator<UnwovenClassFile> iter = input.getClassFileIterator(); iter.hasNext();) { UnwovenClassFile clf = iter.next(); typesToProcess.add(clf.getClassName()); } while (typesToProcess.size() > 0) { //对目标类的父类做处理 weaveParentsFor(typesToProcess, typesToProcess.get(0), null); } //下面的代码太复杂了,看不下去,不知道 Spring 的用意,那我们直接入主题吧 for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); String className = classFile.getClassName(); addNormalTypeMungers(className); } CompilationAndWeavingContext.leavingPhase(typeMungingToken); requestor.weavingAspects(); ContextToken aspectToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); String className = classFile.getClassName(); ResolvedType theType = world.resolve(className); if (theType.isAspect()) { BcelObjectType classType = BcelWorld.getBcelObjectType(theType); if (classType == null) { ReferenceTypeDelegate theDelegate = ((ReferenceType) theType).getDelegate(); if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) { continue; } throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); } weaveAndNotify(classFile, classType, requestor); wovenClassNames.add(className); } } CompilationAndWeavingContext.leavingPhase(aspectToken); requestor.weavingClasses(); ContextToken classToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_CLASSES, ""); for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); String className = classFile.getClassName(); ResolvedType theType = world.resolve(className); if (!theType.isAspect()) { BcelObjectType classType = BcelWorld.getBcelObjectType(theType); if (classType == null) { ReferenceTypeDelegate theDelegate = ((ReferenceType) theType).getDelegate(); if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) { continue; } throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); } //字节码修改和通知 weaveAndNotify(classFile, classType, requestor); wovenClassNames.add(className); } } CompilationAndWeavingContext.leavingPhase(classToken); addedClasses.clear(); deletedTypenames.clear(); requestor.weaveCompleted(); CompilationAndWeavingContext.leavingPhase(weaveToken); if (trace.isTraceEnabled()) { trace.exit("weave", wovenClassNames); } if (world.getModel() != null && world.isMinimalModel()) { candidatesForRemoval.clear(); } return wovenClassNames; }
BcelWeaver.java
private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType, IWeaveRequestor requestor) throws IOException { ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_TYPE, classType .getResolvedTypeX().getName()); //字节码修改和 dump 字节码为 class 文件 LazyClassGen clazz = weaveWithoutDump(classFile, classType); classType.finishedWith(); if (clazz != null) { UnwovenClassFile[] newClasses = getClassFilesFor(clazz); if (newClasses[0].getClassName().equals(classFile.getClassName())) { newClasses[0].setClassNameAsChars(classFile.getClassNameAsChars()); } for (int i = 0; i < newClasses.length; i++) { requestor.acceptResult(newClasses[i]); } } else { requestor.acceptResult(classFile); } classType.weavingCompleted(); CompilationAndWeavingContext.leavingPhase(tok); trace.exit("weaveAndNotify"); }
BcelWeaver.java
private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException { try { //如果类签名字符串中包含$ajc,字节码不需要修改 if (classType.isSynthetic()) { if (dump) { dumpUnchanged(classFile); } return null; } ReferenceType resolvedClassType = classType.getResolvedTypeX(); //如果目标类被配置类的排除类型匹配到,不做字节码修改 if (world.isXmlConfigured() && world.getXmlConfiguration().excludesType(resolvedClassType)) { if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) { world.getMessageHandler().handleMessage( MessageUtil.info("Type '" + resolvedClassType.getName() + "' not woven due to exclusion via XML weaver exclude section")); } if (dump) { dumpUnchanged(classFile); } return null; } //快速过虑掉不匹配的 ShadowMunger List<ShadowMunger> shadowMungers = fastMatch(shadowMungerList, resolvedClassType); List<ConcreteTypeMunger> typeMungers = classType.getResolvedTypeX().getInterTypeMungers(); resolvedClassType.checkInterTypeMungers(); //是否需要去编织 boolean mightNeedToWeave = shadowMungers.size() > 0 || typeMungers.size() > 0 || classType.isAspect() || world.getDeclareAnnotationOnMethods().size() > 0 || world.getDeclareAnnotationOnFields().size() > 0; //桥接方法是否需要去编织 boolean mightNeedBridgeMethods = world.isInJava5Mode() && !classType.isInterface() && resolvedClassType.getInterTypeMungersIncludingSupers().size() > 0; LazyClassGen clazz = null; if (mightNeedToWeave || mightNeedBridgeMethods) { clazz = classType.getLazyClassGen(); try { boolean isChanged = false; if (mightNeedToWeave) { isChanged = BcelClassWeaver.weave(world, clazz, shadowMungers, typeMungers, lateTypeMungerList, inReweavableMode); } checkDeclareTypeErrorOrWarning(world, classType); //对桥接方法处理 if (mightNeedBridgeMethods) { isChanged = BcelClassWeaver.calculateAnyRequiredBridgeMethods(world, clazz) || isChanged; } if (isChanged) { if (dump) { dump(classFile, clazz); } return clazz; } } catch (RuntimeException re) { String classDebugInfo = null; try { classDebugInfo = clazz.toLongString(); } catch (Throwable e) { new RuntimeException("Crashed whilst crashing with this exception: " + e, e).printStackTrace(); classDebugInfo = clazz.getClassName(); } String messageText = "trouble in: \n" + classDebugInfo; getWorld().getMessageHandler().handleMessage(new Message(messageText, IMessage.ABORT, re, null)); } catch (Error re) { String classDebugInfo = null; try { classDebugInfo = clazz.toLongString(); } catch (OutOfMemoryError oome) { System.err.println("Ran out of memory creating debug info for an error"); re.printStackTrace(System.err); classDebugInfo = clazz.getClassName(); } catch (Throwable e) { classDebugInfo = clazz.getClassName(); } String messageText = "trouble in: \n" + classDebugInfo; getWorld().getMessageHandler().handleMessage(new Message(messageText, IMessage.ABORT, re, null)); } } else { checkDeclareTypeErrorOrWarning(world, classType); } AsmManager model = world.getModelAsAsmManager(); if (world.isMinimalModel() && model != null && !classType.isAspect()) { AspectJElementHierarchy hierarchy = (AspectJElementHierarchy) model.getHierarchy(); String pkgname = classType.getResolvedTypeX().getPackageName(); String tname = classType.getResolvedTypeX().getSimpleBaseName(); IProgramElement typeElement = hierarchy.findElementForType(pkgname, tname); if (typeElement != null && hasInnerType(typeElement)) { candidatesForRemoval.add(typeElement); } if (typeElement != null && !hasInnerType(typeElement)) { IProgramElement parent = typeElement.getParent(); if (parent != null) { parent.removeChild(typeElement); if (parent.getKind().isSourceFile()) { removeSourceFileIfNoMoreTypeDeclarationsInside(hierarchy, typeElement, parent); } else { hierarchy.forget(null, typeElement); walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(hierarchy, tname, parent); } } } } if (dump) { dumpUnchanged(classFile); return clazz; } else { if (clazz != null && !clazz.getChildClasses(world).isEmpty()) { return clazz; } return null; } } finally { world.demote(); } }
BcelClassWeaver.java
public static boolean weave(BcelWorld world, LazyClassGen clazz, List<ShadowMunger> shadowMungers, List<ConcreteTypeMunger> typeMungers, List<ConcreteTypeMunger> lateTypeMungers, boolean inReweavableMode) { //准备数据 BcelClassWeaver classWeaver = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers); classWeaver.setReweavableMode(inReweavableMode); //开始编织 boolean b = classWeaver.weave(); return b; }
修改了一个类的字节码,并通过返回值表示是否修改
BcelClassWeaver.java
public boolean weave() { //如果一个类的字节码己经修改,并且该字节码不能被再次修改,直接返回 if (clazz.isWoven() && !clazz.isReweavable()) { if (world.getLint().nonReweavableTypeEncountered.isEnabled()) { world.getLint().nonReweavableTypeEncountered.signal(clazz.getType().getName(), ty.getSourceLocation()); } return false; } Set<String> aspectsAffectingType = null; if (inReweavableMode || clazz.getType().isAspect()) { aspectsAffectingType = new HashSet<String>(); } boolean isChanged = false; //如果类类型是Aspect类型,isChanged=true if (clazz.getType().isAspect()) { isChanged = true; } WeaverStateInfo typeWeaverState = (world.isOverWeaving() ? getLazyClassGen().getType().getWeaverState() : null); //typeMungers对切面类字节码修改 for (ConcreteTypeMunger o : typeMungers) { if (!(o instanceof BcelTypeMunger)) { continue; } BcelTypeMunger munger = (BcelTypeMunger) o; if (typeWeaverState != null && typeWeaverState.isAspectAlreadyApplied(munger.getAspectType())) { continue; } boolean typeMungerAffectedType = munger.munge(this); if (typeMungerAffectedType) { isChanged = true; if (inReweavableMode || clazz.getType().isAspect()) { aspectsAffectingType.add(munger.getAspectType().getSignature()); } } } isChanged = weaveDeclareAtMethodCtor(clazz) || isChanged; isChanged = weaveDeclareAtField(clazz) || isChanged; addedSuperInitializersAsList = new ArrayList<IfaceInitList>(addedSuperInitializers.values()); addedSuperInitializersAsList = PartialOrder.sort(addedSuperInitializersAsList); if (addedSuperInitializersAsList == null) { throw new BCException("circularity in inter-types"); } LazyMethodGen staticInit = clazz.getStaticInitializer(); staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true)); List<LazyMethodGen> methodGens = new ArrayList<LazyMethodGen>(clazz.getMethodGens()); for (LazyMethodGen member : methodGens) { if (!member.hasBody()) { continue; } if (world.isJoinpointSynchronizationEnabled() && world.areSynchronizationPointcutsInUse() && member.getMethod().isSynchronized()) { transformSynchronizedMethod(member); } //对所有的mugger 匹配,将匹配成功的加入到 boolean shadowMungerMatched = match(member); //对所有方法进行匹配,如果匹配成功,则类字节码被修改 if (shadowMungerMatched) { if (inReweavableMode || clazz.getType().isAspect()) { aspectsAffectingType.addAll(findAspectsForMungers(member)); } isChanged = true; } } for (LazyMethodGen methodGen : methodGens) { if (!methodGen.hasBody()) { continue; } implement(methodGen); } if (!initializationShadows.isEmpty()) { List<LazyMethodGen> recursiveCtors = new ArrayList<LazyMethodGen>(); while (inlineSelfConstructors(methodGens, recursiveCtors)) { } positionAndImplement(initializationShadows); } if (lateTypeMungers != null) { for (Iterator<ConcreteTypeMunger> i = lateTypeMungers.iterator(); i.hasNext();) { BcelTypeMunger munger = (BcelTypeMunger) i.next(); if (munger.matches(clazz.getType())) { boolean typeMungerAffectedType = munger.munge(this); if (typeMungerAffectedType) { isChanged = true; if (inReweavableMode || clazz.getType().isAspect()) { aspectsAffectingType.add(munger.getAspectType().getSignature()); } } } } } if (isChanged) { clazz.getOrCreateWeaverStateInfo(inReweavableMode); weaveInAddedMethods(); } if (inReweavableMode) { WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo(true); wsi.addAspectsAffectingType(aspectsAffectingType); wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes()); wsi.setReweavable(true); } else { clazz.getOrCreateWeaverStateInfo(false).setReweavable(false); } for (LazyMethodGen mg : methodGens) { BcelMethod method = mg.getMemberView(); if (method != null) { method.wipeJoinpointSignatures(); } } return isChanged; }
在这里,我们主要看 greetTo 方法是如何匹配的
BcelClassWeaver.java
private boolean match(LazyMethodGen mg) { BcelShadow enclosingShadow; List<BcelShadow> shadowAccumulator = new ArrayList<BcelShadow>(); boolean isOverweaving = world.isOverWeaving(); boolean startsAngly = mg.getName().charAt(0) == '<'; //对于构造方法匹配初始化 if (startsAngly && mg.getName().equals("<init>")) { return matchInit(mg, shadowAccumulator); } else if (!shouldWeaveBody(mg)) {//如果方法是桥接方法 return false; } else { if (startsAngly && mg.getName().equals("<clinit>")) { //对于静态方法或静态属性匹配初始化 enclosingShadow = BcelShadow.makeStaticInitialization(world, mg); } else if (mg.isAdviceMethod()) {//如果是切点方法 enclosingShadow = BcelShadow.makeAdviceExecution(world, mg); } else { AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature(); if (effective == null) { //如果方法名以ajc$开头,并且方法己经被编织了 if (isOverweaving && mg.getName().startsWith(NameMangler.PREFIX)) { return false; } //创建 BcelShadow 对象 enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows); } else if (effective.isWeaveBody()) { ResolvedMember rm = effective.getEffectiveSignature(); fixParameterNamesForResolvedMember(rm, mg.getMemberView()); fixAnnotationsForResolvedMember(rm, mg.getMemberView()); enclosingShadow = BcelShadow.makeShadowForMethod(world, mg, effective.getShadowKind(), rm); } else { return false; } } if (canMatchBodyShadows) { for (InstructionHandle h = mg.getBody().getStart(); h != null; h = h.getNext()) { match(mg, h, enclosingShadow, shadowAccumulator); } } //如果方法匹配中有 munger,但是方法名并不是以 a 或ajc$interFieldInit开头 if (canMatch(enclosingShadow.getKind()) && !(mg.getName().charAt(0) == 'a' && mg.getName().startsWith("ajc$interFieldInit"))) { //开始对每个 munger 进行匹配,并将匹配成功的 munger 加入到shadowAccumulator中 if (match(enclosingShadow, shadowAccumulator)) { //对方法Shadow进行初始化 enclosingShadow.init(); } } mg.matchedShadows = shadowAccumulator; return !shadowAccumulator.isEmpty(); } }
BcelClassWeaver.java
private boolean match(BcelShadow shadow, List<BcelShadow> shadowAccumulator) { if (captureLowLevelContext) { ContextToken shadowMatchToken = CompilationAndWeavingContext.enteringPhase( CompilationAndWeavingContext.MATCHING_SHADOW, shadow); boolean isMatched = false; Shadow.Kind shadowKind = shadow.getKind(); List<ShadowMunger> candidateMungers = indexedShadowMungers[shadowKind.getKey()]; if (candidateMungers != null) { for (ShadowMunger munger : candidateMungers) { ContextToken mungerMatchToken = CompilationAndWeavingContext.enteringPhase( CompilationAndWeavingContext.MATCHING_POINTCUT, munger.getPointcut()); if (munger.match(shadow, world)) { shadow.addMunger(munger); isMatched = true; if (shadow.getKind() == Shadow.StaticInitialization) { clazz.warnOnAddedStaticInitializer(shadow, munger.getSourceLocation()); } } CompilationAndWeavingContext.leavingPhase(mungerMatchToken); } if (isMatched) { shadowAccumulator.add(shadow); } } CompilationAndWeavingContext.leavingPhase(shadowMatchToken); return isMatched; } else { boolean isMatched = false; Shadow.Kind shadowKind = shadow.getKind(); //获取到所有的 munger List<ShadowMunger> candidateMungers = indexedShadowMungers[shadowKind.getKey()]; if (candidateMungers != null) { for (ShadowMunger munger : candidateMungers) { //逐一匹配,匹配成功加入到shadow的 mungers 中 if (munger.match(shadow, world)) { shadow.addMunger(munger); isMatched = true; if (shadow.getKind() == Shadow.StaticInitialization) { clazz.warnOnAddedStaticInitializer(shadow, munger.getSourceLocation()); } } } if (isMatched) { shadowAccumulator.add(shadow); } } return isMatched; } }
ShadowMunger.java
public boolean match(Shadow shadow, World world) { if (world.isXmlConfigured() && world.isAspectIncluded(declaringType)) { TypePattern scoped = world.getAspectScope(declaringType); if (scoped != null) { Set<ResolvedType> excludedTypes = world.getExclusionMap().get(declaringType); ResolvedType type = shadow.getEnclosingType().resolve(world); if (excludedTypes != null && excludedTypes.contains(type)) { return false; } boolean b = scoped.matches(type, TypePattern.STATIC).alwaysTrue(); if (!b) { if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) { world.getMessageHandler().handleMessage( MessageUtil.info("Type '" + type.getName() + "' not woven by aspect '" + declaringType.getName() + "' due to scope exclusion in XML definition")); } if (excludedTypes == null) { excludedTypes = new HashSet<ResolvedType>(); excludedTypes.add(type); world.getExclusionMap().put(declaringType, excludedTypes); } else { excludedTypes.add(type); } return false; } } } if (world.areInfoMessagesEnabled() && world.isTimingEnabled()) { long starttime = System.nanoTime(); FuzzyBoolean isMatch = pointcut.match(shadow); long endtime = System.nanoTime(); world.record(pointcut, endtime - starttime); return isMatch.maybeTrue(); } else { //如果 xml 中没有配置 configure,同时也不需要记录匹配时间,直接执行 pointcut.match()方法来匹配 FuzzyBoolean isMatch = pointcut.match(shadow); return isMatch.maybeTrue(); } }
pointcut.match() 这一行表示切点匹配方法,之前也花了一篇来讲解Spring是如何匹配切点表达式的,Spring源码深度解析(郝佳)-学习-源码解析-aop切面表达式匹配(四),感兴趣的小伙伴可以去研究一下,切点表达式,和我们的方法,或类是如何匹配的。到这里,我们对munger 又做了一层过虑,这也意味着离字节码的修改,也越来越近了。
BcelClassWeaver.java
private void implement(LazyMethodGen mg) { List<BcelShadow> shadows = mg.matchedShadows; if (shadows == null) { return; } for (BcelShadow shadow : shadows) { ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.IMPLEMENTING_ON_SHADOW, shadow); //开始实现修改字节码方法 shadow.implement(); CompilationAndWeavingContext.leavingPhase(tok); } mg.getMaxLocals(); mg.matchedShadows = null; return isChanged; }
public final void implement() { //对所有的 munger 排序 sortMungers(); if (mungers == null) { return; } //切点修改字节码前准备 prepareForMungers(); //真正修改字节码操作代码 implementMungers(); }
Shadow.java
private void sortMungers() { List sorted = PartialOrder.sort(mungers); possiblyReportUnorderedAdvice(sorted); if (sorted == null) { for (ShadowMunger m : mungers) { getIWorld().getMessageHandler().handleMessage( MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY, this), m.getSourceLocation())); } } mungers = sorted; }
PartialOrder.java
public static List sort(List objects) { if (objects.size() < 2) { return objects; } List<SortObject> sortList = new LinkedList<SortObject>(); // objects.size()); for (Iterator i = objects.iterator(); i.hasNext();) { addNewPartialComparable(sortList, (PartialComparable) i.next()); } final int N = objects.size(); for (int index = 0; index < N; index++) { SortObject leastWithNoSmallers = null; for (Iterator i = sortList.iterator(); i.hasNext();) { SortObject so = (SortObject) i.next(); if (so.hasNoSmallerObjects()) { if (leastWithNoSmallers == null || so.object.fallbackCompareTo(leastWithNoSmallers.object) < 0) { leastWithNoSmallers = so; } } } if (leastWithNoSmallers == null) { return null; } removeFromGraph(sortList, leastWithNoSmallers); objects.set(index, leastWithNoSmallers.object); } return objects; }
private static void addNewPartialComparable(List<SortObject> graph, PartialComparable o) { SortObject so = new SortObject(o); for (Iterator<SortObject> i = graph.iterator(); i.hasNext();) { SortObject other = i.next(); so.addDirectedLinks(other); } graph.add(so); }
private static class SortObject { PartialComparable object; List<SortObject> smallerObjects = new LinkedList<SortObject>(); List<SortObject> biggerObjects = new LinkedList<SortObject>(); public SortObject(PartialComparable o) { object = o; } boolean hasNoSmallerObjects() { return smallerObjects.size() == 0; } boolean removeSmallerObject(SortObject o) { smallerObjects.remove(o); return hasNoSmallerObjects(); } void addDirectedLinks(SortObject other) { int cmp = object.compareTo(other.object); if (cmp == 0) { return; } if (cmp > 0) { this.smallerObjects.add(other); other.biggerObjects.add(this); } else { this.biggerObjects.add(other); other.smallerObjects.add(this); } } public String toString() { return object.toString(); } }
这个排序方法看起来很复杂,其实原理很简单,就像小时候上体育课,按照高矮排队,举个例子,小明1.1米,小林1.2 米,小花1.3米,右边低,左边高,开始记录了,
小花,小林,在小明的左边,
小明右边没有人,小林右边是小明,小林左边是小花,
小花的左边没有人,右边是小明,小林。
- 第一轮排序:找出右边没有人的同学,并排在最右边,小明排最右边,将己经排好队的同学小明从其他同学的信息中删除,小林的右边没有人,小林左边是小花,小花右边是小林。
- 第二轮排序:找出右边没有人的同学,找到小林。排在小明后面,将小林信息从其他同学记录信息中删除,小花右边没有人了。
- 第三轮排序:找出右边没有人的同学,找到小花。小花排在小林后面,得到最终从矮到高,小明,小林,小花。
在我们这个方法中,removeFromGraph()方法相当于将挑选出来矮的同学从其他同学的信息中删除操作。
无意中我发现一个问题。
抛出循环通知异常,为什么会出现这种情况呢?问题就出现在排序方法上。为什么 sorted 为 null 呢?
我们打断点查看。
发现第个切点的 smallerObjects都不为空,Spring去找smallerObjects为空的切点,发现没有,因此removeFromGraph()方法就无法进行了。因此sorted 为空,相当于,小明,小林,小花三人比排身高,
- 小明比小林矮
- 小林比小花矮
- 小花又比小明矮
那这个身高没法比了。那我们来看看正常情况下,smallerObjects数据是怎样的呢?我们将 around()方法发到 after()方法前面。
这时,我们发现 around()切点的 smallerObjects为空了,因此,around()切点排在最前面,以此类推,sorted()将不为空,【不过在这里注意一下,我的 jdk 版本是1.7进行测试的】。程序执行正常。
为什么执行结果和源码方法顺序有关系呢?这里我们回顾一下动态代理实现过程,动态代理对切点方法排序算法和静态代理一样。唯一不同的就是compareTo()方法,动态代理 compareTo()方法实现过程。
- A 类实现PriorityOrdered接口,B类实现PriorityOrdered接口,A 类 getOrder()返回1,B 类getOrder()返回2,值越小,切点方法越排在前面。
- A 类配置注解@Order(1),B 类配置@Order(2),注解值越小,方法越排在前面。
- A 类配置注解@Order(2),B 类实现PriorityOrdered接口,方法getOrder()返回1,B 类切点方法排在前面,A 类切点方法排在后面。
- A类配置注解@Order(2),B 类不配置注解@Order,也不实现接口PriorityOrdered,A类切点方法排在前面。
- 同一个切面类的切点方法,先根据配置注解顺序,@Around,@Before,@After,@AfterThrowing,@AfterReturning(),配置@Around()注解的切点方法排在最前面,配置@AfterReturning()注解方法排在最后面。以此类推。
- 在同一个切面类中,同时配置了@Before()方法的切点 ,根据方法名排序 ,方法名越小,越排在前面。如 ab()方法排在 ac()方法前面。
我们来看看静态代理compareTo()方法。
public int compareTo(Object other) { if (!(other instanceof BcelAdvice)) { return 0; } BcelAdvice o = (BcelAdvice) other; if (kind.getPrecedence() != o.kind.getPrecedence()) { if (kind.getPrecedence() > o.kind.getPrecedence()) { return +1; } else { return -1; } } if (kind.isCflow()) { boolean isBelow = (kind == AdviceKind.CflowBelowEntry); if (this.innerCflowEntries.contains(o)) { return isBelow ? +1 : -1; } else if (o.innerCflowEntries.contains(this)) { return isBelow ? -1 : +1; } else { return 0; } } if (kind.isPerEntry() || kind == AdviceKind.Softener) { return 0; } World world = concreteAspect.getWorld(); int ret = concreteAspect.getWorld().compareByPrecedence(concreteAspect, o.concreteAspect); if (ret != 0) { return ret; } //获取当前切点和其他切点的切面类类型 ResolvedType declaringAspect = getDeclaringAspect().resolve(world); ResolvedType o_declaringAspect = o.getDeclaringAspect().resolve(world); if (declaringAspect == o_declaringAspect) { if (kind.isAfter() || o.kind.isAfter()) { //比较start, 那 start 是什么呢? return this.getStart() < o.getStart() ? -1 : +1; } else { return this.getStart() < o.getStart() ? +1 : -1; } } else if (declaringAspect.isAssignableFrom(o_declaringAspect)) { return -1; } else if (o_declaringAspect.isAssignableFrom(declaringAspect)) { return +1; } else { return 0; } }
当两个切点在同一个切面类中时,比较是 start,那 start 是什么呢?先看this是什么吧。我们要排序的是mungers,而mungers是ShadowMunger集合。在 ShadowMuger 构造器中打断点
我发现 start 来源于 AjAttribute.AdviceAttribute,而AjAttribute.AdviceAttribute又是从哪里来的呢?在处理注解有一个这样的方法,handleAroundAnnotation(),在方法中两行这样的代码
ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), struct.bMethod.getDeclarationOffset()); struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Around, pc, extraArgument, sl.getOffset(), sl .getOffset() + 1, struct.context)); }
我们看到 start又来源于sl的getOffset()方法,再来看代码。
ISourceLocation.java
public ISourceLocation makeSourceLocation(int line, int offset) { if (line < 0) { line = 0; } SourceLocation sl = new SourceLocation(getSourceFile(), line); if (offset > 0) { sl.setOffset(offset); } else { if (lineBreaks != null) { int likelyOffset = 0; if (line > 0 && line < lineBreaks.length) { likelyOffset = lineBreaks[line - 1] + 1; } sl.setOffset(likelyOffset); } } return sl; }
从代码上来看,offset 来源于方法所在源码行号和方法所在字节码表的偏移量,而这两个值是怎样提供的呢?
BcelMethod.java
public int getDeclarationLineNumber() { if (declarationLineNumber != null) { return declarationLineNumber.getLineNumber(); } else { return -1; } } public int getDeclarationOffset() { if (declarationLineNumber != null) { return declarationLineNumber.getOffset(); } else { return -1; } }
而这个变量declarationLineNumber又是哪里来的呢?最终发现是在processAttributes()方法中初始化的。
而 AjAttribute是方法的字节码属性attributes,因此,如果我们要设置 start 值,需要在方法的字节码属性中添加MethodDeclarationLineNumber属性。我寻寻觅觅,在网上找了很多办法,都没有找到如何修改方法字节码属性表的办法。最后,无意中发现,使用这种方式,能够产生MethodDeclarationLineNumber属性。
下面,我们来看一个例子。
Hello.java
//https://blog.csdn.net/gavin_john/article/details/80156963 public class Hello { private int a; public String sayHello() { System.out.println("Hello, AspectJ!"); return "xiaoming"; } public static void main(String[] args) { Hello hello = new Hello(); hello.sayHello(); } }
package com.test; public aspect TxAspectj { //切入点 pointcut mypointcut():call(* com.test.Hello.*(..)); //前置增强 before(): mypointcut(){ System.out.println("前置增强"); } //环绕增强 Object around():mypointcut(){ System.out.println("around start..."); Object o = proceed(); System.out.println("around end..."); return o ; } //最终增强 after():mypointcut(){ System.out.println("后置增强"); } //异常增强 after() throwing(Exception e): mypointcut(){ System.out.println("异常增强了"); e.printStackTrace(); } //return增强 after() returning(Object o): mypointcut(){ System.out.println("返回" + o); } }
准备:
关于如何配置 AspectJ 的开发环境,请参考AspectJ——简介以及在IntelliJ IDEA下的配置 这一博客,还是写得很详细的
测试:
//https://blog.csdn.net/gavin_john/article/details/80156963 public static void main(String[] args) throws Exception { File file = new File("/Users/quyixiao/git/testACJ/target/classes/com/test/Hello.class"); InputStream inputStream = new FileInputStream(file); //解析 java 类字节码 ClassParser parser = new ClassParser(inputStream, file.getPath()); JavaClass jc = parser.parse(); Method[] methods = jc.getMethods(); for (Method method : methods) { //得到方法的所有属性表 Attribute[] attributes = method.getAttributes(); for (Attribute attribute : attributes) { System.out.println(method.getName() + "==========" + attribute.getName()); //得到方法属性的名称,如果是MethodDeclarationLineNumber,获取方法行号及方法字节码偏移量 if (attribute.getName().contains("MethodDeclarationLineNumber")) { Unknown u = (Unknown) attribute; BcelConstantPoolReader dataDecompressor = new BcelConstantPoolReader(method.getConstantPool()); VersionedDataInputStream s = new VersionedDataInputStream(new ByteArrayInputStream(u.getBytes()), dataDecompressor); AjAttribute.MethodDeclarationLineNumberAttribute lineInfo = AjAttribute.MethodDeclarationLineNumberAttribute.read(s); System.out.println("lineNumber:" + lineInfo.getLineNumber() + ",offset : " + lineInfo.getOffset()); } } } }
结果:
因此,我们可以以 ACJ 编译方式来修改 start 的值。在测试的过程中发现静态代理有一个小问题,我们在源码中移动环绕通知的位置,将 around()方法移动到after()方法后面。
发现,竟然编译失败。再将代码再移回去,发现又好了,不过为了保证效果,尽量每次在测试前将 target给删除吧。AspectJ 竟然有这样的问题,对于 Spring 静态代理而言,即使我们能通过MethodDeclarationLineNumber设置切点方法的 start,但是我们还是无法将 around()方法移动到 after()方法后面,因此对于静态代理,切点的在源码中的位置是受限制的。这可能也是静态代理没有动态代理使用得广泛的原因吧。本测试的 github地址是https://github.com/quyixiao/testACJ
到这里,我们终于将切点排序讲完了,我们继续来分析prepareForMungers()方法吧。
BcelShadow.java
protected void prepareForMungers() { //如果是构造函数调用,则需要删除new:dup或new:dup_x1:swap,并将所有参数存储在框架中。 //(对于Java语言,这有点hack)。我们这样做是因为在处理编织连接点时,我们有时会添加代码“ outsideBefore”。 //我们只这样做是为了暴露堆栈上的状态。事实证明,它只适用于除了构造函数调用和异常处理程序之外的所有内容。 //如果我们要清理,每个ShadowRange都将具有三个指令句柄点, arg设置代码的开头, //正在运行的代码的开头和正在运行的代码的结尾。 boolean deletedNewAndDup = true; //如果是构造函数调用 if (getKind() == ConstructorCall) { if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) { deletedNewAndDup = deleteNewAndDup(); } initializeArgVars(); } else if (getKind() == PreInitialization) {//如果是preinitialization ShadowRange range = getRange(); range.insert(InstructionConstants.NOP, Range.InsideAfter); } else if (getKind() == ExceptionHandler) { //如果切点类型是异常处理类型 ShadowRange range = getRange(); InstructionList body = range.getBody(); InstructionHandle start = range.getStart(); argVars = new BcelVar[1]; UnresolvedType tx = getArgType(0); argVars[0] = genTempVar(tx, "ajc$arg0"); InstructionHandle insertedInstruction = range.insert(argVars[0].createStore(getFactory()), Range.OutsideBefore); for (InstructionTargeter t : start.getTargetersCopy()) { if (t instanceof ExceptionRange) { ExceptionRange er = (ExceptionRange) t; er.updateTarget(start, insertedInstruction, body); } } } isThisJoinPointLazy = true; badAdvice = null; for (ShadowMunger munger : mungers) { //初始化exposedState,初始化切点方法参数变量,并对切点运行时测试,如果配置是 Around()切点,则对JoinPoint 等参数处理 munger.specializeOn(this); } //对ProceedingJoinPoint,JoinPoint 切点方法参数处理 initializeThisJoinPoint(); if (thisJoinPointVar != null && !isThisJoinPointLazy && badAdvice != null && badAdvice.size() > 1) { int valid = 0; for (Iterator<BcelAdvice> iter = badAdvice.iterator(); iter.hasNext();) { BcelAdvice element = iter.next(); ISourceLocation sLoc = element.getSourceLocation(); if (sLoc != null && sLoc.getLine() > 0) { valid++; } } if (valid != 0) { ISourceLocation[] badLocs = new ISourceLocation[valid]; int i = 0; for (Iterator<BcelAdvice> iter = badAdvice.iterator(); iter.hasNext();) { BcelAdvice element = iter.next(); ISourceLocation sLoc = element.getSourceLocation(); if (sLoc != null) { badLocs[i++] = sLoc; } } world.getLint().multipleAdviceStoppingLazyTjp .signal(new String[] { this.toString() }, getSourceLocation(), badLocs); } } badAdvice = null; InstructionFactory fact = getFactory(); if (getKind().argsOnStack() && argVars != null) { if (getKind() == ExceptionHandler && range.getEnd().getNext().getInstruction().equals(InstructionConstants.POP)) { range.getEnd().getNext().setInstruction(InstructionConstants.NOP); } else { range.insert(BcelRenderer.renderExprs(fact, world, argVars), Range.InsideBefore); if (targetVar != null) { range.insert(BcelRenderer.renderExpr(fact, world, targetVar), Range.InsideBefore); } if (getKind() == ConstructorCall) { if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) { if (deletedNewAndDup) { range.insert(InstructionFactory.createDup(1), Range.InsideBefore); range.insert(fact.createNew((ObjectType) BcelWorld.makeBcelType(getSignature().getDeclaringType())), Range.InsideBefore); } } } } } }
BcelAdvice.java
private void implementMungers() { World world = getIWorld(); for (ShadowMunger munger : mungers) { //遍历所有能够对方法织入的切点,对方法进行织入 if (munger.implementOn(this)) { //织入后通知 world.reportMatch(munger, this); } } }
BcelAdvice.java
public boolean implementOn(Shadow s) { hasMatchedAtLeastOnce = true; if (aspectIsBroken()) { return false; } BcelShadow shadow = (BcelShadow) s; if (!shadow.getWorld().isIgnoringUnusedDeclaredThrownException() && !getThrownExceptions().isEmpty()) { Member member = shadow.getSignature(); if (member instanceof BcelMethod) { removeUnnecessaryProblems((BcelMethod) member, ((BcelMethod) member).getDeclarationLineNumber()); } else { ResolvedMember resolvedMember = shadow.getSignature().resolve(shadow.getWorld()); if (resolvedMember instanceof BcelMethod && shadow.getEnclosingShadow() instanceof BcelShadow) { Member enclosingMember = shadow.getEnclosingShadow().getSignature(); if (enclosingMember instanceof BcelMethod) { removeUnnecessaryProblems((BcelMethod) enclosingMember, ((BcelMethod) resolvedMember).getDeclarationLineNumber()); } } } } if (shadow.getIWorld().isJoinpointSynchronizationEnabled() && shadow.getKind() == Shadow.MethodExecution && (s.getSignature().getModifiers() & Modifier.SYNCHRONIZED) != 0) { shadow.getIWorld().getLint().advisingSynchronizedMethods.signal(new String[] { shadow.toString() }, shadow.getSourceLocation(), new ISourceLocation[] { getSourceLocation() }); } //如果运行时测试为 false,直接返回 if (runtimeTest == Literal.FALSE) { Member sig = shadow.getSignature(); if (sig.getArity() == 0 && shadow.getKind() == Shadow.MethodCall && sig.getName().charAt(0) == 'c' && sig.getReturnType().equals(ResolvedType.OBJECT) && sig.getName().equals("clone")) { return false; } } //@Before 注解处理 if (getKind() == AdviceKind.Before) { shadow.weaveBefore(this); //@AfterReturning 注解处理 } else if (getKind() == AdviceKind.AfterReturning) { shadow.weaveAfterReturning(this); //@AfterThrowing注解处理 } else if (getKind() == AdviceKind.AfterThrowing) { UnresolvedType catchType = hasExtraParameter() ? getExtraParameterType() : UnresolvedType.THROWABLE; shadow.weaveAfterThrowing(this, catchType); //@After 注解处理 } else if (getKind() == AdviceKind.After) { shadow.weaveAfter(this); //@Around注解处理 } else if (getKind() == AdviceKind.Around) { LazyClassGen enclosingClass = shadow.getEnclosingClass(); if (enclosingClass != null && enclosingClass.isInterface() && shadow.getEnclosingMethod().getName().charAt(0) == '<') { shadow.getWorld().getLint().cannotAdviseJoinpointInInterfaceWithAroundAdvice.signal(shadow.toString(), shadow.getSourceLocation()); return false; } if (!canInline(s)) { shadow.weaveAroundClosure(this, hasDynamicTests()); } else { shadow.weaveAroundInline(this, hasDynamicTests()); } } else if (getKind() == AdviceKind.InterInitializer) { shadow.weaveAfterReturning(this); } else if (getKind().isCflow()) { shadow.weaveCflowEntry(this, getSignature()); } else if (getKind() == AdviceKind.PerThisEntry) { shadow.weavePerObjectEntry(this, (BcelVar) shadow.getThisVar()); } else if (getKind() == AdviceKind.PerTargetEntry) { shadow.weavePerObjectEntry(this, (BcelVar) shadow.getTargetVar()); } else if (getKind() == AdviceKind.Softener) { shadow.weaveSoftener(this, ((ExactTypePattern) exceptionType).getType()); } else if (getKind() == AdviceKind.PerTypeWithinEntry) { shadow.weavePerTypeWithinAspectInitialization(this, shadow.getEnclosingType()); } else { throw new BCException("unimplemented kind: " + getKind()); } return true; }
看到了weaveBefore()方法,终于有一种熬到头的感觉。但是实际情况告诉你,离完成还差得远呢?毫无疑问,我们进入weaveBefore()方法
BcelShadow.java
void weaveBefore(BcelAdvice munger) { range.insert(munger.getAdviceInstructions(this, null, range.getRealStart()), Range.InsideBefore); }
BcelAdvice.java
InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) { BcelShadow shadow = s; InstructionFactory fact = shadow.getFactory(); BcelWorld world = shadow.getWorld(); InstructionList il = new InstructionList(); //对方法额外参数处理 if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) { UnresolvedType extraParameterType = getExtraParameterType(); if (!extraParameterType.equals(UnresolvedType.OBJECT) && !extraParameterType.isPrimitiveType()) { il.append(BcelRenderer.renderTest(fact, world, Test.makeInstanceof(extraArgVar, getExtraParameterType().resolve(world)), null, ifNoAdvice, null)); } } //增强常量池属性及方法调用 il.append(getAdviceArgSetup(shadow, extraArgVar, null)); //同理,这个方法主要是增加了对切点方法的调用 il.append(getNonTestAdviceInstructions(shadow)); InstructionHandle ifYesAdvice = il.getStart(); il.insert(getTestInstructions(shadow, ifYesAdvice, ifNoAdvice, ifYesAdvice)); //如果目标方法是method-execution类型,切点是 Before,增加方法行号表和局部变量表 if (shadow.getKind() == Shadow.MethodExecution && getKind() == AdviceKind.Before) { int lineNumber = 0; lineNumber = shadow.getEnclosingMethod().getMemberView().getLineNumberOfFirstInstruction(); InstructionHandle start = il.getStart(); if (lineNumber > 0) { //修正行号表 start.addTargeter(new LineNumberTag(lineNumber)); } LocalVariableTable lvt = shadow.getEnclosingMethod().getMemberView().getMethod().getLocalVariableTable(); if (lvt != null) { LocalVariable[] lvTable = lvt.getLocalVariableTable(); for (int i = 0; i < lvTable.length; i++) { LocalVariable lv = lvTable[i]; if (lv.getStartPC() == 0) { //修正局部变量表 start.addTargeter(new LocalVariableTag(lv.getSignature(), lv.getName(), lv.getIndex(), 0)); } } } } return il; }
BcelAdvice.java
public InstructionList getAdviceArgSetup(BcelShadow shadow, BcelVar extraVar, InstructionList closureInstantiation) { InstructionFactory fact = shadow.getFactory(); BcelWorld world = shadow.getWorld(); InstructionList il = new InstructionList(); //如果切面类实例不为空,也就是PreGreetingAspect.aspectOf()方法调用值不为空 if (exposedState.getAspectInstance() != null) { //其实静态切,就是在切面中提供一个单例切面对象,目标类方法中引入切面对象,调用切面中的切点方法。 //下面就是创建切面单例对象实现过程 il.append(BcelRenderer.renderExpr(fact, world, exposedState.getAspectInstance())); } boolean x = this.getDeclaringAspect().resolve(world).isAnnotationStyleAspect(); final boolean isAnnotationStyleAspect = getConcreteAspect() != null && getConcreteAspect().isAnnotationStyleAspect() && x; boolean previousIsClosure = false; //如果切点方法中有额外参数如ProceedingJoinPoint,JoinPoint,JoinPoint.StaticPart的方法参数处理 for (int i = 0, len = exposedState.size(); i < len; i++) { if (exposedState.isErroneousVar(i)) { continue; // Erroneous vars have already had error msgs reported! } BcelVar v = (BcelVar) exposedState.get(i); if (v == null) { if (!isAnnotationStyleAspect) { } else { if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) { if (getKind() != AdviceKind.Around) { previousIsClosure = false; getConcreteAspect() .getWorld() .getMessageHandler() .handleMessage( new Message("use of ProceedingJoinPoint is allowed only on around advice (" + "arg " + i + " in " + toString() + ")", this.getSourceLocation(), true)); il.append(InstructionConstants.ACONST_NULL); } else { if (previousIsClosure) { il.append(InstructionConstants.DUP); } else { previousIsClosure = true; il.append(closureInstantiation.copy()); } } } else if ("Lorg/aspectj/lang/JoinPoint$StaticPart;".equals(getSignature().getParameterTypes()[i] .getSignature())) { previousIsClosure = false; if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) { shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact); } } else if ("Lorg/aspectj/lang/JoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) { previousIsClosure = false; if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { il.append(shadow.loadThisJoinPoint()); } } else if ("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".equals(getSignature().getParameterTypes()[i] .getSignature())) { previousIsClosure = false; if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) { shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact); } } else if (hasExtraParameter()) { previousIsClosure = false; extraVar.appendLoadAndConvert(il, fact, getExtraParameterType().resolve(world)); } else { previousIsClosure = false; getConcreteAspect() .getWorld() .getMessageHandler() .handleMessage( new Message("use of ProceedingJoinPoint is allowed only on around advice (" + "arg " + i + " in " + toString() + ")", this.getSourceLocation(), true)); il.append(InstructionConstants.ACONST_NULL); } } } else { UnresolvedType desiredTy = getBindingParameterTypes()[i]; v.appendLoadAndConvert(il, fact, desiredTy.resolve(world)); } } //非注解类型的切面处理 if (!isAnnotationStyleAspect) { if (getKind() == AdviceKind.Around) { il.append(closureInstantiation); } else if (hasExtraParameter()) { extraVar.appendLoadAndConvert(il, fact, getExtraParameterType().resolve(world)); } //主要是对JoinPoint.StaticPart参数处理 if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) { shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact); } //JoinPoint参数处理 if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { il.append(shadow.loadThisJoinPoint()); } if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) { shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact); } } return il; }
BcelRenderer.java
public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e) { BcelRenderer renderer = new BcelRenderer(fact, world); e.accept(renderer); return renderer.instructions; }
BcelRenderer.java
public void visit(CallExpr call) { Member method = call.getMethod(); Expr[] args = call.getArgs(); InstructionList callIl = renderExprs(fact, world, args); callIl.append(Utility.createInvoke(fact, world, method)); instructions.insert(callIl); }
public static Instruction createInvoke(InstructionFactory fact, BcelWorld world, Member signature) { short kind; //获取方法修饰符 int signatureModifiers = signature.getModifiers(); //如果方法修饰符是接口类型 if (Modifier.isInterface(signatureModifiers)) { kind = Constants.INVOKEINTERFACE; } else if (Modifier.isStatic(signatureModifiers)) {//如果是静态 kind = Constants.INVOKESTATIC; } else if (Modifier.isPrivate(signatureModifiers) || signature.getName().equals("<init>")) { //如果是私有或构造方法 kind = Constants.INVOKESPECIAL; } else { //普通方法调用 kind = Constants.INVOKEVIRTUAL; } //获取方法所有类的类型 UnresolvedType targetType = signature.getDeclaringType(); if (targetType.isParameterizedType()) { targetType = targetType.resolve(world).getGenericType(); } return fact.createInvoke(targetType.getName(), signature.getName(), BcelWorld.makeBcelType(signature.getReturnType()), BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind); }
不过在这里,我要提一下,如何根据signatureModifiers判断当前是 static类型,首先getModifiers()这是方法的基本属性,将返回一个整数,如返回9 ,从下面类的访问标识符和16进制对应关系表得到9是0x0001和0x0008相加的值,因此,方法或属性的修饰符是 public static 。
InstructionFactory.java
public InvokeInstruction createInvoke(String class_name, String name, Type ret_type, Type[] arg_types, short kind) { String signature = Utility.toMethodSignature(ret_type, arg_types); int index; //如果当前方法修饰符是invokeinterface if (kind == Constants.INVOKEINTERFACE) { index = cp.addInterfaceMethodref(class_name, name, signature); //如果当前方法修饰符是invokedynamic } else if (kind == Constants.INVOKEDYNAMIC){ throw new IllegalStateException("NYI"); } else { index = cp.addMethodref(class_name, name, signature); } switch (kind) { case Constants.INVOKESPECIAL: return new InvokeInstruction(Constants.INVOKESPECIAL, index); case Constants.INVOKEVIRTUAL: return new InvokeInstruction(Constants.INVOKEVIRTUAL, index); //构建方法指令 //也就是修改 字节码表中的 Code //当然,在这里是调用静态方法PreGreetingAspect.aspectOf(),返回值为PreGreetingAspect类型 //增加如下指令: //0: invokestatic #41 // Method com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; case Constants.INVOKESTATIC: return new InvokeInstruction(Constants.INVOKESTATIC, index); case Constants.INVOKEINTERFACE: int nargs = 0; for (int i = 0; i < arg_types.length; i++) { nargs += arg_types[i].getSize(); } return new INVOKEINTERFACE(index, nargs + 1, 0); default: throw new RuntimeException("Oops: Unknown invoke kind:" + kind); } }
ConstantPool.java
public int addMethodref(String class_name, String method_name, String signature) { int ret, class_index, name_and_type_index; if ((ret = lookupMethodref(class_name, method_name, signature)) != -1) return ret; //常量池扩容,每次长度加3 adjustSize(); //添加方法名称,返回值类型,以及名称返回值类型索引 //#36 = Utf8 aspectOf //#37 = Utf8 ()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; //#38 = NameAndType #36:#37 // aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; name_and_type_index = addNameAndType(method_name, signature); //添加方法类索引 //#39 = Utf8 com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect //#40 = Class #39 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect //#41 = Methodref #40.#38 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; class_index = addClass(class_name); ret = poolSize; //构建常量池方法引用 pool[poolSize++] = new ConstantMethodref(class_index, name_and_type_index); return ret; }
ConstantPool.java
public int lookupMethodref(String searchClassname, String searchMethodName, String searchSignature) { String key = new StringBuffer().append(searchClassname).append(searchMethodName).append(searchSignature).toString(); Integer cached = methodCache.get(key); if (cached != null) return cached.intValue(); searchClassname = searchClassname.replace('.', '/'); for (int i = 1; i < poolSize; i++) { Constant c = pool[i]; if (c != null && c.tag == Constants.CONSTANT_Methodref) { ConstantMethodref cfr = (ConstantMethodref) c; ConstantNameAndType cnat = (ConstantNameAndType) pool[cfr.getNameAndTypeIndex()]; int cIndex = cfr.getClassIndex(); ConstantClass cc = (ConstantClass) pool[cIndex]; //获取常量池中方法所在类名 String cName = ((ConstantUtf8) pool[cc.getNameIndex()]).getValue(); if (!cName.equals(searchClassname)) continue; //获取常量池中方法的方法名 String name = ((ConstantUtf8) pool[cnat.getNameIndex()]).getValue(); if (!name.equals(searchMethodName)) continue; //从常量池中获取方法修饰符 String typeSignature = ((ConstantUtf8) pool[cnat.getSignatureIndex()]).getValue(); if (!typeSignature.equals(searchSignature)) continue; methodCache.put(key, new Integer(i)); return i; } } return -1; }
lookupMethodref()这个方法主要是看常量池中是否有方法的常量池信息。
程序执行到这里,我们终于对getAdviceArgSetup()这个方法理解了,这个方法主要目的是在目标方法就去中增加aspectOf()方法调用,获取切面类的实例,其中主要包括在目标类中修改常量池属性,增加方法引用,修改目标方法的 Code属性,增加调用指令。
程序执行到这里。己经完成了对 Waiter.class 文件字节码修改。看下面图,我们知道,对于@Before切面,最终在目标方法中增加了PreGreetingAspect.aspectOf().beforeTest();这一行代码调用,PreGreetingAspect.aspectOf()获取到PreGreetingAspect实例,beforeTest()方法,调用切点方法,从而实现了代理 。
Waiter.class 原字节码
Classfile /Users/quyixiao/git/spring_tiny/_ajdump/_before/com/spring_1_100/test_91_100/test97_ltw/Waiter.class Last modified 2020-11-17; size 641 bytes MD5 checksum 38b247a0bda216a85c65a672f6f05550 Compiled from "Waiter.java" public class com.spring_1_100.test_91_100.test97_ltw.Waiter minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #7.#21 // java/lang/Object."":()V #2 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #24 // xxxxxxxxxxxxxx #4 = Methodref #25.#26 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = String #27 // b #6 = Class #28 // com/spring_1_100/test_91_100/test97_ltw/Waiter #7 = Class #29 // java/lang/Object #8 = Utf8 #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 LocalVariableTable #13 = Utf8 this #14 = Utf8 Lcom/spring_1_100/test_91_100/test97_ltw/Waiter; #15 = Utf8 greetTo #16 = Utf8 (Ljava/lang/String;)Ljava/lang/String; #17 = Utf8 name #18 = Utf8 Ljava/lang/String; #19 = Utf8 SourceFile #20 = Utf8 Waiter.java #21 = NameAndType #8:#9 // "":()V #22 = Class #30 // java/lang/System #23 = NameAndType #31:#32 // out:Ljava/io/PrintStream; #24 = Utf8 xxxxxxxxxxxxxx #25 = Class #33 // java/io/PrintStream #26 = NameAndType #34:#35 // println:(Ljava/lang/String;)V #27 = Utf8 b #28 = Utf8 com/spring_1_100/test_91_100/test97_ltw/Waiter #29 = Utf8 java/lang/Object #30 = Utf8 java/lang/System #31 = Utf8 out #32 = Utf8 Ljava/io/PrintStream; #33 = Utf8 java/io/PrintStream #34 = Utf8 println #35 = Utf8 (Ljava/lang/String;)V { public com.spring_1_100.test_91_100.test97_ltw.Waiter(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/spring_1_100/test_91_100/test97_ltw/Waiter; public java.lang.String greetTo(java.lang.String); descriptor: (Ljava/lang/String;)Ljava/lang/String; flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String xxxxxxxxxxxxxx 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: ldc #5 // String b 10: areturn LineNumberTable: line 6: 0 line 7: 8 LocalVariableTable: Start Length Slot Name Signature 0 11 0 this Lcom/spring_1_100/test_91_100/test97_ltw/Waiter; 0 11 1 name Ljava/lang/String; } SourceFile: "Waiter.java"
Waiter.class 代理后字节码
Classfile /Users/quyixiao/git/spring_tiny/_ajdump/com/spring_1_100/test_91_100/test97_ltw/Waiter.class Last modified 2020-11-17; size 914 bytes MD5 checksum 642293d3255675e3ea07a313f1c45830 Compiled from "Waiter.java" public class com.spring_1_100.test_91_100.test97_ltw.Waiter minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #7.#21 // java/lang/Object."":()V #2 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #24 // xxxxxxxxxxxxxx #4 = Methodref #25.#26 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = String #27 // b #6 = Class #28 // com/spring_1_100/test_91_100/test97_ltw/Waiter #7 = Class #29 // java/lang/Object #8 = Utf8 #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 LocalVariableTable #13 = Utf8 this #14 = Utf8 Lcom/spring_1_100/test_91_100/test97_ltw/Waiter; #15 = Utf8 greetTo #16 = Utf8 (Ljava/lang/String;)Ljava/lang/String; #17 = Utf8 name #18 = Utf8 Ljava/lang/String; #19 = Utf8 SourceFile #20 = Utf8 Waiter.java #21 = NameAndType #8:#9 // "":()V #22 = Class #30 // java/lang/System #23 = NameAndType #31:#32 // out:Ljava/io/PrintStream; #24 = Utf8 xxxxxxxxxxxxxx #25 = Class #33 // java/io/PrintStream #26 = NameAndType #34:#35 // println:(Ljava/lang/String;)V #27 = Utf8 b #28 = Utf8 com/spring_1_100/test_91_100/test97_ltw/Waiter #29 = Utf8 java/lang/Object #30 = Utf8 java/lang/System #31 = Utf8 out #32 = Utf8 Ljava/io/PrintStream; #33 = Utf8 java/io/PrintStream #34 = Utf8 println #35 = Utf8 (Ljava/lang/String;)V #36 = Utf8 aspectOf #37 = Utf8 ()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #38 = NameAndType #36:#37 // aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #39 = Utf8 com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect #40 = Class #39 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect #41 = Methodref #40.#38 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #42 = Utf8 beforeTest #43 = NameAndType #42:#9 // beforeTest:()V #44 = Methodref #40.#43 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.beforeTest:()V #45 = Utf8 org.aspectj.weaver.WeaverVersion #46 = Utf8 org.aspectj.weaver.WeaverState { public com.spring_1_100.test_91_100.test97_ltw.Waiter(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/spring_1_100/test_91_100/test97_ltw/Waiter; LineNumberTable: line 3: 0 public java.lang.String greetTo(java.lang.String); descriptor: (Ljava/lang/String;)Ljava/lang/String; flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: invokestatic #41 // Method com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; 3: invokevirtual #44 // Method com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.beforeTest:()V 6: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 9: ldc #3 // String xxxxxxxxxxxxxx 11: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: ldc #5 // String b 16: areturn LocalVariableTable: Start Length Slot Name Signature 0 17 0 this Lcom/spring_1_100/test_91_100/test97_ltw/Waiter; 0 17 1 name Ljava/lang/String; LineNumberTable: line 6: 0 line 7: 14 } SourceFile: "Waiter.java" Error: unknown attribute org.aspectj.weaver.WeaverVersion: length = 0xC 00 07 00 00 00 00 00 00 00 00 00 00 Error: unknown attribute org.aspectj.weaver.WeaverState: length = 0x4 03 00 00 00
对于 Waiter 目标类的字节码修改,我们分析到这里就结束了。我们再来分析切面类的字节码修改。
BcelPerClauseAspectAdder.java
public boolean munge(BcelClassWeaver weaver) { LazyClassGen gen = weaver.getLazyClassGen(); //对并不是内部类并且方法类型是perobject处理 doAggressiveInner(gen); if (!gen.getType().equals(aspectType)) { return false; } return doMunge(gen, true); }
private boolean doMunge(LazyClassGen gen, boolean checkAlreadyThere) { if (checkAlreadyThere && hasPerClauseMembersAlready(gen)) { return false; } //初始化ajc$perSingletonInstance及ajc$initFailureCause信息 generatePerClauseMembers(gen); if (kind == PerClause.SINGLETON) { //issingleton处理 generatePerSingletonAspectOfMethod(gen); generatePerSingletonHasAspectMethod(gen); generatePerSingletonAjcClinitMethod(gen); } else if (kind == PerClause.PEROBJECT) { //perobject处理 generatePerObjectAspectOfMethod(gen); generatePerObjectHasAspectMethod(gen); generatePerObjectBindMethod(gen); } else if (kind == PerClause.PERCFLOW) { //percflow处理 generatePerCflowAspectOfMethod(gen); generatePerCflowHasAspectMethod(gen); generatePerCflowPushMethod(gen); generatePerCflowAjcClinitMethod(gen); } else if (kind == PerClause.PERTYPEWITHIN) { //pertypewithin处理 generatePerTWAspectOfMethod(gen); generatePerTWHasAspectMethod(gen); generatePerTWGetInstanceMethod(gen); generatePerTWCreateAspectInstanceMethod(gen); generatePerTWGetWithinTypeNameMethod(gen); } else { throw new Error("should not happen - not such kind " + kind.getName()); } return true; }
这里,我们对单例类型进行分析了
private void generatePerClauseMembers(LazyClassGen classGen) { ResolvedMember failureFieldInfo = AjcMemberMaker.initFailureCauseField(aspectType); //初始化ajc$initFailureCause if (kind == PerClause.SINGLETON) { classGen.addField(makeFieldGen(classGen, failureFieldInfo), null); } if (kind == PerClause.SINGLETON) { //ajc$perSingletonInstance ResolvedMember perSingletonFieldInfo = AjcMemberMaker.perSingletonField(aspectType); classGen.addField(makeFieldGen(classGen, perSingletonFieldInfo), null); } else if (kind == PerClause.PERCFLOW) { ResolvedMember perCflowFieldInfo = AjcMemberMaker.perCflowField(aspectType); classGen.addField(makeFieldGen(classGen, perCflowFieldInfo), null); } else if (kind == PerClause.PERTYPEWITHIN) { ResolvedMember perTypeWithinForField = AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType); classGen.addField(makeFieldGen(classGen, perTypeWithinForField), null); } }
ajc$perSingletonInstance在切面类中添加 public static final 类型的属性$perSingletonInstance。在后面的静态代码块中初始化此值。
private void generatePerSingletonAspectOfMethod(LazyClassGen classGen) { InstructionFactory factory = classGen.getFactory(); //创建PreGreetingAspect.aspectOf()方法 LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perSingletonAspectOfMethod(aspectType)); flagAsSynthetic(method, false); classGen.addMethodGen(method); InstructionList il = method.getBody(); //0: getstatic #44 // Field ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; il.append(Utility.createGet(factory, AjcMemberMaker.perSingletonField(aspectType))); //3: ifnonnull 19 InstructionBranch ifNotNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); il.append(ifNotNull); //6: new #46 // class org/aspectj/lang/NoAspectBoundException il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); //9: dup il.append(InstructionConstants.DUP); //10: ldc #48 // String com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect il.append(InstructionFactory.PUSH(classGen.getConstantPool(), aspectType.getName())); //12: getstatic #50 // Field ajc$initFailureCause:Ljava/lang/Throwable; il.append(Utility.createGet(factory, AjcMemberMaker.initFailureCauseField(aspectType))); //15: invokespecial #53 // Method org/aspectj/lang/NoAspectBoundException."":(Ljava/lang/String;Ljava/lang/Throwable;)V il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, new Type[] { Type.STRING, new ObjectType("java.lang.Throwable") }, Constants.INVOKESPECIAL)); //18: athrow il.append(InstructionConstants.ATHROW); //19: getstatic #44 // Field ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; InstructionHandle ifElse = il.append(Utility.createGet(factory, AjcMemberMaker.perSingletonField(aspectType))); //22: areturn il.append(InstructionFactory.createReturn(Type.OBJECT)); ifNotNull.setTarget(ifElse); }
这个方法看上去一大堆,实际上是创建下面的aspectOf()方法
public static PreGreetingAspect aspectOf() { if (ajc$perSingletonInstance == null) { throw new NoAspectBoundException("com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect", ajc$initFailureCause); } else { return ajc$perSingletonInstance; } }
BcelPerClauseAspectAdder.java
private void generatePerSingletonHasAspectMethod(LazyClassGen classGen) { InstructionFactory factory = classGen.getFactory(); //创建静态hasAspect()方法 LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perSingletonHasAspectMethod(aspectType)); flagAsSynthetic(method, false); classGen.addMethodGen(method); InstructionList il = method.getBody(); //0: getstatic #44 // Field ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; il.append(Utility.createGet(factory, AjcMemberMaker.perSingletonField(aspectType))); //3: ifnull 8 InstructionBranch ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); il.append(ifNull); //6: iconst_1 il.append(InstructionFactory.PUSH(classGen.getConstantPool(), true)); //7: ireturn il.append(InstructionFactory.createReturn(Type.INT)); //8: iconst_0 InstructionHandle ifElse = il.append(InstructionFactory.PUSH(classGen.getConstantPool(), false)); //9: ireturn il.append(InstructionFactory.createReturn(Type.INT)); ifNull.setTarget(ifElse); }
创建 hasAspect()方法
public static boolean hasAspect() { return ajc$perSingletonInstance != null; }
创建静态代码块初始化切面类方法
private void generatePerSingletonAjcClinitMethod(LazyClassGen classGen) { InstructionFactory factory = classGen.getFactory(); //创建 acj$postClinit()方法 LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.ajcPostClinitMethod(aspectType)); flagAsSynthetic(method, true); classGen.addMethodGen(method); //创建ajc$postClinit();方法 InstructionList il = method.getBody(); //new PreGreetingAspect()对象 il.append(factory.createNew(aspectType.getName())); il.append(InstructionConstants.DUP); il.append(factory.createInvoke(aspectType.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); //为ajc$perSingletonInstance设置值 il.append(Utility.createSet(factory, AjcMemberMaker.perSingletonField(aspectType))); //return void 类型 il.append(InstructionFactory.createReturn(Type.VOID)); //创建静态代码块 LazyMethodGen clinit = classGen.getStaticInitializer(); il = new InstructionList(); //构建try catch,try 开始 InstructionHandle tryStart = //1: invokestatic #57 // Method ajc$postClinit:()V //调用上面创建的ajc$postClinit il.append(factory.createInvoke(aspectType.getName(), NameMangler.AJC_POST_CLINIT_NAME, Type.VOID, Type.NO_ARGS, Constants.INVOKESTATIC)); InstructionBranch tryEnd = InstructionFactory.createBranchInstruction(Constants.GOTO, null); // try 结束 il.append(tryEnd); InstructionHandle handler = il.append(InstructionConstants.ASTORE_0); il.append(InstructionConstants.ALOAD_0); //如果方法抛出异常,则将异常堆栈信息赋值给ajc$initFailureCause变量 il.append(Utility.createSet(factory, AjcMemberMaker.initFailureCauseField(aspectType))); il.append(InstructionFactory.createReturn(Type.VOID)); tryEnd.setTarget(il.getEnd()); if (clinit.getBody().getEnd().getInstruction().opcode == Constants.IMPDEP1) { clinit.getBody().getEnd().getPrev().setInstruction(InstructionConstants.NOP); } clinit.getBody().getEnd().setInstruction(InstructionConstants.NOP); clinit.getBody().append(il); clinit.addExceptionHandler(tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Throwable"), false); }
这个方法的创建,主要是对切面类实例的初始化,之前我们定义了ajc$perSingletonInstance变量,在这个方法中对静态变量初始化,对应的 java 代码
static { try { ajc$postClinit(); } catch (Throwable var1) { ajc$initFailureCause = var1; } }
到这里,我们终于完成了PreGreetingAspect字节码修改的分析,字节码修改对比如下。
PreGreetingAspect原字节码
Classfile /Users/quyixiao/git/spring_tiny/_ajdump/_before/com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.class Last modified 2020-11-17; size 934 bytes MD5 checksum 00770cd67a41fe5d1ee0078520efd18b Compiled from "PreGreetingAspect.java" public class com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#25 // java/lang/Object."":()V #2 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #19 // beforeTest #4 = Methodref #28.#29 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #30 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect #6 = Class #31 // java/lang/Object #7 = Utf8 #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #14 = Utf8 test #15 = Utf8 RuntimeVisibleAnnotations #16 = Utf8 Lorg/aspectj/lang/annotation/Pointcut; #17 = Utf8 value #18 = Utf8 execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..)) && args(..) #19 = Utf8 beforeTest #20 = Utf8 Lorg/aspectj/lang/annotation/Before; #21 = Utf8 test() #22 = Utf8 SourceFile #23 = Utf8 PreGreetingAspect.java #24 = Utf8 Lorg/aspectj/lang/annotation/Aspect; #25 = NameAndType #7:#8 // "":()V #26 = Class #32 // java/lang/System #27 = NameAndType #33:#34 // out:Ljava/io/PrintStream; #28 = Class #35 // java/io/PrintStream #29 = NameAndType #36:#37 // println:(Ljava/lang/String;)V #30 = Utf8 com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect #31 = Utf8 java/lang/Object #32 = Utf8 java/lang/System #33 = Utf8 out #34 = Utf8 Ljava/io/PrintStream; #35 = Utf8 java/io/PrintStream #36 = Utf8 println #37 = Utf8 (Ljava/lang/String;)V { public com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; public void test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String beforeTest 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 14: 0 line 15: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; RuntimeVisibleAnnotations: 0: #16(#17=s#18) public void beforeTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String beforeTest 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 21: 0 line 22: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; RuntimeVisibleAnnotations: 0: #20(#17=s#21) } SourceFile: "PreGreetingAspect.java" RuntimeVisibleAnnotations: 0: #24()
PreGreetingAspect代理后字节码
quyixiao@quyixiaodeMacBook-Pro ~/git/spring_tiny/_ajdump/com/spring_1_100/test_91_100/test97_ltw master ●✚ javap -verbose PreGreetingAspect.class Classfile /Users/quyixiao/git/spring_tiny/_ajdump/com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.class Last modified 2020-11-17; size 1835 bytes MD5 checksum ee5275d1e179d9bf66a9ef4066577862 Compiled from "PreGreetingAspect.java" public class com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#25 // java/lang/Object."":()V #2 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #19 // beforeTest #4 = Methodref #28.#29 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #30 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect #6 = Class #31 // java/lang/Object #7 = Utf8 #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #14 = Utf8 test #15 = Utf8 RuntimeVisibleAnnotations #16 = Utf8 Lorg/aspectj/lang/annotation/Pointcut; #17 = Utf8 value #18 = Utf8 execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..)) && args(..) #19 = Utf8 beforeTest #20 = Utf8 Lorg/aspectj/lang/annotation/Before; #21 = Utf8 test() #22 = Utf8 SourceFile #23 = Utf8 PreGreetingAspect.java #24 = Utf8 Lorg/aspectj/lang/annotation/Aspect; #25 = NameAndType #7:#8 // "":()V #26 = Class #32 // java/lang/System #27 = NameAndType #33:#34 // out:Ljava/io/PrintStream; #28 = Class #35 // java/io/PrintStream #29 = NameAndType #36:#37 // println:(Ljava/lang/String;)V #30 = Utf8 com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect #31 = Utf8 java/lang/Object #32 = Utf8 java/lang/System #33 = Utf8 out #34 = Utf8 Ljava/io/PrintStream; #35 = Utf8 java/io/PrintStream #36 = Utf8 println #37 = Utf8 (Ljava/lang/String;)V #38 = Utf8 Synthetic #39 = Utf8 ajc$initFailureCause #40 = Utf8 Ljava/lang/Throwable; #41 = Utf8 ajc$perSingletonInstance #42 = Utf8 org.aspectj.weaver.AjSynthetic #43 = NameAndType #41:#13 // ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #44 = Fieldref #5.#43 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #45 = Utf8 org/aspectj/lang/NoAspectBoundException #46 = Class #45 // org/aspectj/lang/NoAspectBoundException #47 = Utf8 com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect #48 = String #47 // com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect #49 = NameAndType #39:#40 // ajc$initFailureCause:Ljava/lang/Throwable; #50 = Fieldref #5.#49 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.ajc$initFailureCause:Ljava/lang/Throwable; #51 = Utf8 (Ljava/lang/String;Ljava/lang/Throwable;)V #52 = NameAndType #7:#51 // "":(Ljava/lang/String;Ljava/lang/Throwable;)V #53 = Methodref #46.#52 // org/aspectj/lang/NoAspectBoundException."":(Ljava/lang/String;Ljava/lang/Throwable;)V #54 = Methodref #5.#25 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect."":()V #55 = Utf8 ajc$postClinit #56 = NameAndType #55:#8 // ajc$postClinit:()V #57 = Methodref #5.#56 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.ajc$postClinit:()V #58 = Utf8 aspectOf #59 = Utf8 ()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #60 = Utf8 hasAspect #61 = Utf8 ()Z #62 = Utf8 #63 = Utf8 java/lang/Throwable #64 = Class #63 // java/lang/Throwable #65 = NameAndType #58:#59 // aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #66 = Methodref #5.#65 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; #67 = NameAndType #19:#8 // beforeTest:()V #68 = Methodref #5.#67 // com/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect.beforeTest:()V #69 = Utf8 org.aspectj.weaver.WeaverVersion #70 = Utf8 org.aspectj.weaver.WeaverState #71 = Utf8 StackMapTable { public static final com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect ajc$perSingletonInstance; descriptor: Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL Synthetic: true public com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; LineNumberTable: line 8: 0 public void test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: invokestatic #66 // Method aspectOf:()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; 3: invokevirtual #68 // Method beforeTest:()V 6: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 9: ldc #3 // String beforeTest 11: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: return LocalVariableTable: Start Length Slot Name Signature 0 15 0 this Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; LineNumberTable: line 14: 0 line 15: 14 RuntimeVisibleAnnotations: 0: #16(#17=s#18) public void beforeTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String beforeTest 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; LineNumberTable: line 21: 0 line 22: 8 RuntimeVisibleAnnotations: 0: #20(#17=s#21) public static com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect aspectOf(); descriptor: ()Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=0, args_size=0 0: getstatic #44 // Field ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; 3: ifnonnull 19 6: new #46 // class org/aspectj/lang/NoAspectBoundException 9: dup 10: ldc #48 // String com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect 12: getstatic #50 // Field ajc$initFailureCause:Ljava/lang/Throwable; 15: invokespecial #53 // Method org/aspectj/lang/NoAspectBoundException."":(Ljava/lang/String;Ljava/lang/Throwable;)V 18: athrow 19: getstatic #44 // Field ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; 22: areturn LineNumberTable: line 1: 0 StackMapTable: number_of_entries = 1 frame_type = 19 /* same */ Error: unknown attribute org.aspectj.weaver.AjSynthetic: length = 0x0 public static boolean hasAspect(); descriptor: ()Z flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #44 // Field ajc$perSingletonInstance:Lcom/spring_1_100/test_91_100/test97_ltw/PreGreetingAspect; 3: ifnull 8 6: iconst_1 7: ireturn 8: iconst_0 9: ireturn LineNumberTable: line 1: 0 StackMapTable: number_of_entries = 1 frame_type = 8 /* same */ Error: unknown attribute org.aspectj.weaver.AjSynthetic: length = 0x0 static {}; descriptor: ()V flags: ACC_STATIC Code: stack=1, locals=1, args_size=0 0: nop 1: invokestatic #57 // Method ajc$postClinit:()V 4: goto 12 7: astore_0 8: aload_0 9: putstatic #50 // Field ajc$initFailureCause:Ljava/lang/Throwable; 12: return Exception table: from to target type 1 7 7 Class java/lang/Throwable LineNumberTable: line 1: 0 StackMapTable: number_of_entries = 2 frame_type = 71 /* same_locals_1_stack_item */ stack = [ class java/lang/Throwable ] frame_type = 4 /* same */ } SourceFile: "PreGreetingAspect.java" RuntimeVisibleAnnotations: 0: #24() Error: unknown attribute org.aspectj.weaver.WeaverVersion: length = 0xC 00 07 00 00 00 00 00 00 00 00 00 00 Error: unknown attribute org.aspectj.weaver.WeaverState: length = 0x4 03 00 00 00
经过整篇博客分析,我们终于理解了 Spring静态代理的过程。但是这篇博客只对@Before切点的分析,是最简单的静态代理了,虽然简单,但是也是面面具到了,这里,我们再来对修改后的类字节码回顾一下。
Waiter.class
public class Waiter { public Waiter() { } public String greetTo(String name) { //获取切面实例,调用切点方法 PreGreetingAspect.aspectOf().beforeTest(ajc$tjp_0); System.out.println("xxxxxxxxxxxxxx"); return "b"; } static { ajc$preClinit(); } }
PreGreetingAspect.class
@Aspect public class PreGreetingAspect { public final static ajc$perSingletonInstance = null; public final static ajc$initFailureCause = null; public PreGreetingAspect() { } @Pointcut("execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..)) && args(..)") public void test() { //test()方法也被execution(* com.spring_1_100.test_91_100.test97_ltw.*.*(..))切到了 aspectOf().beforeTest(); System.out.println("beforeTest"); } @Before("test()") public void beforeTest() { System.out.println("beforeTest"); } public static PreGreetingAspect aspectOf() { if (ajc$perSingletonInstance == null) { throw new NoAspectBoundException("com.spring_1_100.test_91_100.test97_ltw.PreGreetingAspect", ajc$initFailureCause); } else { return ajc$perSingletonInstance; } } public static boolean hasAspect() { return ajc$perSingletonInstance != null; } static { try { ajc$postClinit(); } catch (Throwable var1) { ajc$initFailureCause = var1; } } public void ajc$postClinit(){ ajc$perSingletonInstance = new PreGreetingAspect(); } }
其中红色的代码是类字节码增加的代码,蓝色的代码,是根据java 字节码修改代码分析出来的。当看到字节码结构,我们终于明白,原来 Spring静态是通过这种方式来实现的。
流程:
1)transform():FilteringClassFileTransformer的transform()方法 1)transform():AspectJClassBypassingClassFileTransformer的transform()方法 1)preProcess():ClassPreProcessorAgentAdapter预处理方法 1)getWeaver():Aj.WeaverContainer.getWeaver() 获取编织适配器 1)getWeavingAdaptor(): 1)initialize():初始化 aop.xml 等文件的参数 1)initialize(): 1)new DefaultWeavingContext(classLoader): 2)createMessageHandler():创建消息处理器,主要用于在控制台打印日志消息 3)getDefinitions():获取所有的aop.xml中的标签定义 1)parseDefinitions(): 解析定义 1)DocumentParser.parse(configFile.toURL()): 1)saxParsing(): 1) xmlReader.parse(): xml读取器解析 4)registerDefinitions(): 注册定义 1)registerOptions(): 注册aop.xml标签中所有options选项 2)registerAspectExclude():注册切面表达式中所有exlude的表达式 3)registerAspectInclude():注册所有切面表达式中所有include 表达式 4)registerAspects():注册所有切面 5)registerIncludeExclude(): 6)registerDump(): 注册是不是需要 dump字节码 5)prepareForWeave():编织前准备 1)rewritePointcuts(this.shadowMungerList): 重写切点 1)weaveClass(): 1)couldWeave(): 目标方法是否能编织 1)accept(): 1)getWovenBytes():获取目标编织后的类字节码 1)weave(): 1)weaveAndNotify(): 编织成功并打印消息 1)weaveWithoutDump(): 1)weave(): 1)weave(): 1)implement(): 开始编织 1)shadow.implement(): 1)sortMungers(): 对切点排序 2)prepareForMungers(): 切点参数设置 3)implementMungers(): 真正编织 1)implementOn(): 1)weaveBefore(): @Before切点编织 2)weaveAfterReturning(): @AfterReturni切点编织 3)weaveAfterThrowing(): @AfterThrowing切点编织 4)weaveAfter(): @After 切点编织 5)weaveAround():@Around切点编织 6)weaveAfterReturning():@AfterReturning切点编织 2)dumpOnExit():dump字节码文件并退出
问题:
这篇博客是比较长的,我觉得一般人,只是看看的话,肯定不知道在说些什么,前面大部分代码都是在讲参数的初始化,平平无奇,但是又不得不解析,不然,都不知道这些切点,表达式的匹配是怎样来的,而真真的重点在后面,修改字节码,但是这需要对java 字节码结构有所了解的同学才看得懂。所以,如果对字节码不太了解的同学,可以先去学习一下java 类字节码结构,再来研究这一块。
总结:
静态代理相对于动态代理 :
- 优点:
AOP 的静态代理主要是在虚拟机启动时通过改变目标对象字节码的方式来完成对目标对象的增强,它与动态代理相比具有更高的效率,因此在动态代理调用过程中,还需要创建代理并代理目标对象的步骤,而静态代理则是在启动时便完成了字节码增强,当系统再次调用目标与调用正常类并无差别,所以在效率上会更加高些。 - 缺点:
正如前面测试的那样,我们将源码中around()方法放到after()方法后面,发现竟然实现不了静态代理,也就是静态代理还和切点在源码中的位置相关,在我的环境中发现这个问题,不知道其他的环境有没有这个问题,至少带来了使用上的不方便。
静态代理需要vm options参数中加入-javaagent:-javaagent:/path/spring-instrument-4.2.1.RELEASE.jar,需要在每个环境中都添加 vm 参数,如果是线上项目,需要在测试,预发,线上都配置,带来项目发布上的不方便。
经过上面的分析,静态代理虽然性能更好,但用起来不是很方便。我建义,还是用动态代理吧。
疑问:
我们只对Before切点进行了分析,若换成
public Object aroundTest(ProceedingJoinPoint p) { System.out.println("around before1"); Object o = null; try { o = p.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("around after1"); return o; }
Spring又是如何增强呢?
本文的 github 地址是https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_1_100/test_91_100/test97_ltw