- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
7.5.2 自定义标签
在 Spring 中如果需要使用 AspectJ 的功能,首先要做的第一步就是在配置文件中加入配置:<context:load-time-weaver/>。我们根据之前介绍的自定义命名空间的知识便可以推断,引用 AspectJ 的入口便是这里,可以通过查找 load-time-weaver 来找到对应的自定义命名处理类。
通过 Eclipse 提供的字符串搜索功能,我们找到了 ContextNamespaceHandler,在其中有这样一段函数。
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholder
BeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBean
DefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBean
DefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinition
Parser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinition
Parser());
registerBeanDefinitionParser("Spring-configured", new SpringConfiguredBeanDefinition
Parser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
继续跟进 LoadTimeWeaverBeanDefinitionParser,作为 BeanDefinitionParser 接口的实现类,他的核心逻辑是从 parse 函数开始的,而经过父类的封装,LoadTimeWeaverBeanDefinitionParser 类的核心实现被转移到了 doParse 函数中,如下:
protected void doParse(Element element, ParserContext parserContext, BeanDefinition
Builder builder) {
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE),
parserContext)) {
RootBeanDefinition weavingEnablerDef = new RootBeanDefinition();
// ASPECTJ_WEAVING_ENABLER_CLASS_NAME =
// "org.Springframework.context.weaving.AspectJWeavingEnabler";
weavingEnablerDef.setBeanClassName(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);
parserContext.getReaderContext().registerWithGeneratedName(weavingEnablerDef);
if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBean
ClassLoader())) {
new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
}
}
}
其实之前在分析动态 AOP 也就是在分析配置<aop:aspectj-autoproxy />中已经提到了自定义配置的解析流程,对于<aop:aspectj-autoproxy/>的解析无非是以标签作为标志,进而进行相关处理类的注册,那么对于自定义标签<context:load-time-weaver />其实是起到了同样的作用。
上面函数的核心作用其实就是注册一个对于 ApectJ 处理的类 org.Springframework.context. weaving.AspectJWeavingEnabler,它的注册流程总结起来如下。
(1)是否开启 AspectJ。
之前虽然反复提到了在配置文件中加入了<context:load-time-weaver/>便相当于加入了 AspectJ 开关。但是,并不是配置了这个标签就意味着开启了 AspectJ 功能,这个标签中还有一个属性 aspectj-weaving,这个属性有 3 个备选值,on、off 和 autodetect,默认为 autodetect,也就是说,如果我们只是使用了<context:load-time-weaver/>,那么 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 {
//自动检测
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。
尽管在 init 方法中注册了 AspectJWeavingEnabler,但是对于标签本身 Spring 也会以 bean 的形式保存,也就是当 Spring 解析到<context:load-time-weaver/>标签的时候也会产生一个 bean,而这个 bean 中的信息是什么呢?
在 LoadTimeWeaverBeanDefinitionParser 类中有这样的函数:
@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;
}
其中,可以看到:
WEAVER_CLASS_ATTRIBUTE="weaver-class"
DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME =
"org.Springframework.context.weaving.DefaultContextLoadTimeWeaver";
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME=”loadTimeWeaver”
单凭以上的信息我们至少可以推断,当 Spring 在读取到自定义标签<context:load-time-weaver/>后会产生一个 bean,而这个 bean 的 id 为 loadTimeWeaver,class 为 org.Springframework.context.weaving. DefaultContextLoadTimeWeaver,也就是完成了 DefaultContextLoadTimeWeaver 类的注册。
完成了以上的注册功能后,并不意味这在 Spring 中就可以使用 AspectJ 了,因为我们还有一个很重要的步骤忽略了,就是 LoadTimeWeaverAwareProcessor 的注册。在 AbstractApplicationContext 中的 prepareBeanFactory 函数中有这样一段代码:
//增加对 AspectJ 的支持
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
(beanFactory));
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader (beanFactory.
getBeanClassLoader()));
}
在 AbstractApplicationContext 中的 prepareBeanFactory 函数是在容器初始化时候调用的,也就是说只有注册了 LoadTimeWeaverAwareProcessor 才会激活整个 AspectJ 的功能。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论