返回介绍

7.5.2 自定义标签

发布于 2025-04-22 22:09:14 字数 5482 浏览 0 评论 0 收藏

在 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 的功能。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。