中北软院创新实验室Java 杂谈

Spring 标签<context:annotation-

2017-11-24  本文已影响42人  HikariCP

前言


在学习Spring的过程中,自己算是好好体会了一把Spring配置文件的繁琐。不切实体会一下就不知道有多让人不爽,众多的配置文件不说,关键是一个功能一个配置文件,而且十分容易忘记。那我们应该怎么办呢?记住他们吗?一定不是,懂得学习的人是不会花过多时间刻意去记那些数不清的schema以及标签的。我们只需要记录即可,记录我们常用的配置,并进行整理。用到即取,不是很方便吗?

在学习Spring的时候,过多的标签总会使我记了又忘忘了又记。搞得自己总是很狼狈,反复学习却效果不是很好。究其原因是用的不多,可是我们也知道,一个项目我们在写的时候从来都是先搭好骨架再进行核心逻辑代码的编写,所以配置文件基本上在一个项目开始的时候就配置的差不多了,一个项目我们做上几个月。时隔很久,我们只有在第一次配置配置文件的时候才算脑中过了一下配置文件中某些配置的概念。所以说,这种东西是和用的多少没有关系的很明显。就连Spring官方代码,都积极的给我们提供了示例项目供我们参考,可见官方也不推荐我们去记住那么众多的配置文件,只是记住有这个东西存在就好,我们用到的时候只要去查阅引入配置标签即可。

今天在编写Spring项目的时候,由于自己最近都在开发SpringBoot相关的内容。所以长期不接触Spring最明显的问题就是配置文件不会写了。过去自己写的时候也一直都是能自己写出来的自己写,写不出来忘记了的的copy原来项目的配置文件。因为具体到业务代码的编写,很明显业务代码才是我们一个程序员应该关注的事情而不是去花大量的时间去搞配置文件,尤其是对于用过SpringBoot的我来说,真的再也受不了去死记硬背那些众多的配置文件了。

问题


开启Spring项目第一件事就是先配置不然你什么都做不了。首先我想要在项目中用我常用的注解@Autowired,我需要在配置文件中声明AutowiredAnnotationBeanPostProcessor这个bean。我又想要在项目中用到@Required这个注解,那我还需要再配置RequiredAnnotationBeanPostProcesso这个bean。一个功能一个bean搞得自己有点儿头大。后来查阅到要想支持这两个注解只需要在配置文件中声明<context:annotation-config/>该标签即可。这个标签自己以前常用,只知道它能为我提供一些注解的支持,但是具体到他能做多少我自己却没有深入研究过。今天就来研究一下,也算是为后续的的Spring标签的探索先踩踩坑。

深入源码


这里我只是简单记录一下我好奇的地方,并记录自己解惑的过程。先上一段代码:

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:annotation-config/>

</beans>

我们来看一下官方对该标签的说明:

As always, you can register them as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the context namespace)

翻译过来:

与往常一样,您可以将它们注册为单独的bean定义,但也可以通过在基于XML的Spring配置中包含以下标记来隐式注册它们(注意包含上下文名称空间)

img

既然官网这么说,可是那么<context:annotation-config/>这个标签什么时候起作用的呢?哪儿体现了他实例化了这几个bean了?

在Spring容器解析配置文件中时,会加载beans标签中配置的URL,如图:

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/context                            http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

我们按住Ctrl点击该标签进入到该目录下:

image

可以看到代码提供的注释这里写的很清楚,该标签提供了哪些注解的支持

image

然后我们再根据配置文件中beans标签中配置的xsi:schemaLocation的URL到spring.handlers文件中,找到对应的NamespaceHandler

比如我上面的是<http://www.springframework.org/schema/context>那么将对应spring.handlers文件中的ContextNamespaceHandler。然后Ctrl B进入

image image

那么这个Handler是做什么的呢?就一个方法,在该方法中,可以看到它的作用就是创建这些标签所对应的解析类。什么是解析类呢?也就是所有的自定义命名空间(像mvccontext等)下的标签解析都是由BeanDefinitionParser接口的子类来完成的。可以看到annotation-config的解析类是AnnotationConfigBeanDefinitionParser

我们继续Ctrl B进入该类,看一下这个类如何解析这个标签的。

image

根据上面的代码可以看出真正的解析是在AnnotationConfigUtils.registerAnnotationConfigProcessors()方法中进行的
那就进去这个方法看看

这里代码篇幅太长,我们贴了代码:

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, Object source) {

        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
        // ConfigurationClassPostProcessor
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // AutowiredAnnotationBeanPostProcessor
        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // RequiredAnnotationBeanPostProcessor
        if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // CommonAnnotationBeanPostProcessor
        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        // PersistenceAnnotationBeanPostProcessor
        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
                ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
                def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        return beanDefs;
}

到这里我们的问题就完美解决了。由代码可以看出,分别注册了AutowiredAnnotationBeanPostProcessorRequiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor以及PersistenceAnnotationBeanPostProcessorConfigurationClassPostProcessor这5个BeanPostProcessor。

上一篇下一篇

猜你喜欢

热点阅读