AOP静态代理解析1-标签解析
AOP静态代理使用示例见Spring的LoadTimeWeaver(代码织入)
Instrumentation使用示例见java.lang.instrument使用
AOP的静态代理主要是在虚拟机启动时通过改变目标对象字节码的方式来完成对目标对象的增强,它与动态代理相比具有更高的效率,因为在动态代理调用的过程中,还需要一个动态创建代理类并代理目标对象的步骤,而静态代理则是在启动时便完成了字节码增强,当系统再次调用目标类时与调用正常的类并无差别,所以在效率上会相对高些。
AspectJ所做的事
在Spring中的静态AOP直接使用了AspectJ提供的方法,而AspectJ又是在Instrument基础上进行的封装。就以上面的两个使用示例来看,至少在AspectJ中会有如下功能。
(1)读取META-INF/aop.xml。
(2)将aop.xml中定义的增强器通过自定义的ClassFileTransformer织入对应的类中。
这都是AspectJ所做的事情,并不在我们讨论的范畴,Spring是直接使用AspectJ,也就是将动态代理的任务直接委托给了AspectJ,那么,Spring怎么嵌入AspectJ的呢?从配置文件入手。
标签解析入口
spring.handlers
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
继续跟进LoadTimeWeaverBeanDefinitionParser,作为BeanDefinitionParser接口的实现类,他的核心逻辑是从parse函数开始的,而经过父类的封装,LoadTimeWeaverBeanDefinitionParser类的核心实现被转移到了doParse函数中
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {
RootBeanDefinition weavingEnablerDef = new RootBeanDefinition();
weavingEnablerDef.setBeanClassName(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);
parserContext.getReaderContext().registerWithGeneratedName(weavingEnablerDef);
if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {
new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
}
}
}
其实之前在分析动态AOP也就是在分析配置中已经提到了自定义配置的解析流程,对于的解析无非是以标签作为标志,进而进行相关处理类的注册,那么对于自定义标签其实是起到了同样的作用。上面函数的核心作用其实就是注册一个对于ApectJ处理的类org.Springframework.context.weaving.AspectJWeavingEnabler,它的注册流程总结起来如下。
(1)是否开启AspectJ。
<context:load-time-weaver aspectj-weaving="autodetect" />
这个标签中还有一个属性aspectj-weaving,这个属性有3个备选值,on、off和autodetect,默认为autodetect,也就是说,如果我们只是使用了,那么Spring会帮助我们检测是否可以使用AspectJ功能,而检测的依据便是文件META-INF/aop.xml是否存在,看看在Spring中的实现方式。
protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) {
if ("on".equals(value)) {
return true;
}
else if ("off".equals(value)) {
return false;
}
else {
// Determine default...
ClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader();
return (cl.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) != null);
}
}
(2)将org.Springframework.context.weaving.AspectJWeavingEnabler封装在BeanDefinition中注册。
当通过AspectJ功能验证后便可以进行AspectJWeavingEnabler的注册了,注册的方式很简单,无非是将类路径注册在新初始化的RootBeanDefinition中,在RootBeanDefinition的获取时会转换成对应的class。(weavingEnablerDef.setBeanClassName(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);)尽管在init方法中注册了AspectJWeavingEnabler,但是对于标签本身Spring也会以bean的形式保存,也就是当Spring解析到标签的时候也会产生一个bean,而这个bean中的信息是什么呢?
在LoadTimeWeaverBeanDefinitionParser类中有这样的函数:
private static final String WEAVER_CLASS_ATTRIBUTE = "weaver-class";
private static final String ASPECTJ_WEAVING_ATTRIBUTE = "aspectj-weaving";
private static final String DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME =
"org.springframework.context.weaving.DefaultContextLoadTimeWeaver";
private static final String ASPECTJ_WEAVING_ENABLER_CLASS_NAME =
"org.springframework.context.weaving.AspectJWeavingEnabler";
@Override
protected String getBeanClassName(Element element) {
if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) {
return element.getAttribute(WEAVER_CLASS_ATTRIBUTE);
}
return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME;
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME;//loadTimeWeaver
}
其中,可以看到:
WEAVER_CLASS_ATTRIBUTE="weaver-class"
DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME ="org.Springframework.context.weaving.DefaultContextLoadTimeWeaver";
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME=”loadTimeWeaver”
凭以上的信息我们至少可以推断,当Spring在读取到自定义标签后会产生一个bean,而这个bean的id为loadTimeWeaver,class为org.Springframework.context.weaving.DefaultContextLoadTimeWeaver,也就是完成了DefaultContextLoadTimeWeaver类的注册。
完成了以上的注册功能后,并不意味这在Spring中就可以使用AspectJ了,因为我们还有一个很重要的步骤忽略了,就是LoadTimeWeaverAwareProcessor的注册。在AbstractApplicationContext中的prepareBeanFactory函数中有这样一段代码:
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {//loadTimeWeaver
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader (beanFactory.getBeanClassLoader()));
}
在AbstractApplicationContext中的prepareBeanFactory函数是在容器初始化时候调用的,也就是说只有注册了LoadTimeWeaverAwareProcessor才会激活整个AspectJ的功能。
总结:
在解析load-time-weaver标签时,从getBeanClassName方法中可以看到,如果没有指定weaver-class属性,会自动给容器中注入一个org.springframework.context.weaving.DefaultContextLoadTimeWeaver类型的bean,从resolveId方法中看到,该bean的名称为loadTimeWeaver。在doParse方法中,还会注册一个类型为org.springframework.context.weaving.AspectJWeavingEnabler的匿名bean。
从此可以看出下面两段配置完全是等价的:
<bean id="loadTimeWeaver"
class="org.springframework.context.weaving.DefaultContextLoadTimeWeaver"></bean>
<bean class="org.springframework.context.weaving.AspectJWeavingEnabler"></bean>
<context:load-time-weaver aspectj-weaving="autodetect" />
与
<context:load-time-weaver aspectj-weaving="autodetect" />
AOP静态代理解析1-标签解析的更多相关文章
- Dubbo原理和源码解析之标签解析
一.Dubbo 配置方式 Dubbo 支持多种配置方式: XML 配置:基于 Spring 的 Schema 和 XML 扩展机制实现 属性配置:加载 classpath 根目录下的 dubbo.pr ...
- spring——AOP(静态代理、动态代理、AOP)
一.代理模式 代理模式的分类: 静态代理 动态代理 从租房子开始讲起:中介与房东有同一的目标在于租房 1.静态代理 静态代理角色分析: 抽象角色:一般使用接口或者抽象类来实现(这里为租房接口) pub ...
- spring(AOP)静态代理
姓名:黄于霞 班级:软件151 1.定义抽象主题接口,假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: 2.主题类,算术类,实现抽象接口. 3.代理类 4.测试运行 5.总 ...
- AOP静态代理解析2-代码织入
当我们完成了所有的AspectJ的准备工作后便可以进行织入分析了,首先还是从LoadTimeWeaverAwareProcessor开始. LoadTimeWeaverAwareProcessor实现 ...
- Spring源码学习笔记之基于ClassPathXmlApplicationContext进行bean标签解析
bean 标签在spring的配置文件中, 是非常重要的一个标签, 即便现在boot项目比较流行, 但是还是有必要理解bean标签的解析流程,有助于我们进行 基于注解配置, 也知道各个标签的作用,以及 ...
- mybatis源码配置文件解析之二:解析settings标签
在前边的博客中分析了mybatis解析properties标签,<mybatis源码配置文件解析之一:解析properties标签>.下面来看解析settings标签的过程. 一.概述 在 ...
- Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring
上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...
- Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC
一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: package com.zhangguo.Spring041.aop01; public class Mat ...
- 【spring 3】AOP:静态代理
一.代理的基本简介 首先,在什么时候使用代理: 在面向方面编程过程中,当需要对所有类进行某种操作(如,安全性检查,记录操作日志)时,考虑到OCP原则,我们不能在所有实现类中直接添加某些相关方法,这样一 ...
随机推荐
- a byte of python(摘03)
a byte of python 第七章 模块 想要在其他程序中重用很多函数,那么你该如何编写程序呢? 答案是使用模块. 模块基本上就是一个包含了所有你定义的函数和变量的文件.为了在其他程序中重用模块 ...
- 留只脚印(DP)
题目链接:http://codeforces.com/problemset/problem/698/A 很久很久没做咯~~~~ dp 是个很神奇的东西.... #include <iostrea ...
- HTML中表格元素TABLE,TR,TD及属性的语法
table:表格元素及属性 <table width="80%" border="1" cellspacing="1" cellpad ...
- 解决sqlite3_key的问题
报错内容显示如下: ld: warning: ignoring file /Users/rowling/Library/Developer/Xcode/DerivedData/zhinengbango ...
- 移动端hrml模板
<!DOCTYPE html><html><head> <title>时钟</title> <meta charset="u ...
- spring集成activeMQ
1.安装activehttp://activemq.apache.org/activemq-5140-release.html2.运行D:\apache-activemq-5.14.0\bin\win ...
- hdu1722(gcd)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1722 题意:要使一块蛋糕既能均分给a个人,又能均分给b个人,问至少需要分成几块(不需要每块都一样大小) ...
- PHP之MVC项目实战(二)
本文主要包括以下内容 GD库图片操作 利用GD库实现验证码 文件上传 缩略图 水印 GD库图片操作 <?php $img = imagecreatetruecolor(500, 300); // ...
- 两个viewport的故事(第二部分)
原文:http://www.quirksmode.org/mobile/viewports2.html 在这个迷你系列的文章里边我将会解释viewport,以及许多重要元素的宽度是如何工作的,比如&l ...
- php 上传文件实例 注册账号
注册界面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...