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原则,我们不能在所有实现类中直接添加某些相关方法,这样一 ...
随机推荐
- div+css进度条
效果图: 进度条代码: <style type="text/css"> 红色:background-color:f05153:border:1px solid #f05 ...
- Android 运行时权限处理
引言 Android 6.0 (API 23) 开始引入了运行时权限检查 (Permissions at Run Time),用户不需要在安装时同意授予应用权限,而是在应用运行时动态去申请所需要的权限 ...
- 从API请求数据的方法(主要适用于tp5)
// 从api获取数据,$data是一个数组,默认为空,请求数据的方法可以通用,但是其它说明只适用于tp5 function postData($url,$data=''){ $ch = curl_i ...
- 【leetcode】Decode Ways(medium)
A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' - ...
- 【XLL API 函数】 xlFree
用于释放使用 Excel4,Excel4v,Excel12,Excel12v 分配的 XLOPER/XLOPER12 占用的内存资源. xlFree 函数释放辅助内存和重置指针为NULL但不释放XLO ...
- sql 查询表的所有详细信息
SELECT (case when a.colorder=1 then d.name else '' end) as 表名,--如果表名相同就返回空 a.colorder as 字段序号, a.nam ...
- MongoDB配置文件YAML-based选项全解
配置文件部分 MongoDB引入一个YAML-based格式的配置文件.2.4版本以前的仍然兼容. 我的mongodb配置文件: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
- mongoDB 3.0以前版本 - 入门指南、示例
一.准备工作 1. 下载mongoDB 下载地址:http://www.mongodb.org/downloads 选择合适你的版本 相关文档:http://www.mongodb.org/displ ...
- NYOJ题目839合并
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAskAAAKgCAIAAADmrHcoAAAgAElEQVR4nO3dO1LsOheG4X8S5AyE2A
- NYOJ之水仙花数
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsAAAAInCAIAAAAZDHiCAAAgAElEQVR4nO3dPVLjzNoG4G8T5CyEFC