Spring注解解析

578 阅读4分钟

Spring注解解析+

关键点须知

xml自定义标签Component-Scan解析

参考资料

IOC自定义标签解析流程相关资料

Component-Scan自定义标签相关解析文档

ComponentScanBeanDefinitionParser.parse来解析

[Spring IOC流程.xmind](./xmind/Spring IOC流程.xmind)

@Configuration解析原理

@Configuration解析的相关资料

[Spring java config解析.xmind](./xmind/Spring java config解析.xmind)

@ComponentScan解析原理

@Configuration解析的相关资料

[Spring java config解析.xmind](./xmind/Spring java config解析.xmind)

总体来说就是使用ComponentScanAnnotationParser.parse来解析区别自定义标签Component-Scan的解析

SpringMVC启动容器

主要关注DispatcherServlet的实现方式

SpringMVC相关资料

SpringBoot启动容器

SpringBoot启动容器相关资料

情况1-xml + Component-Scan标签 + SpringMVC + external Tomcat

配置

web.xml

<web-app>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <!-- map all requests for /app/* to the dispatcher servlet -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!--注解扫描-->
    <context:component-scan base-package="com.acme"/>

</beans>

ServletConfig.java

@Configuration
@ImportXml("classpath:app.xml")
@ComponentScan("com.acme")
@Component
public class ServletConfig {
    @Bean(primary=Primary.TRUE)
    public Service myService() {
        return new Service();
    }

    @Bean
    public Service backupService() {
        return new Service();
    }
}

分析

注册DispatcherServlet

DispatcherServlet启动SpringMVC启动容器XmlWebApplicationContext。参考SpringMVC方式配置的默认容器

Spring扫描自定义标签Component-Scan,解析自定义标签的时候,使用了ComponentScanBeanDefinitionParser。参考xml自定义标签Component-Scan解析

ComponentScanBeanDefinitionParser.parse进行注解标签解析。通过扫描@Component注解往Spring容器中注册了ServletConfig配置。同事,注册了ConfigurationPostProcessor。

在ApplicationContext调用refresh的时候,调用invokeBeanFactoryPostProcessors()的方法时候,会时候ConfigurationClassPostProcessor对加载进来的JavaConfig BeanDefinition进行解析(注意,这里是一定Spring已经加载的Bean)。

ConfigurationClassPostProcessor的@Configuration的解析。参考**@Configuration解析原理**

情况2-javaconfig入口 + xml + SpringMVC + external Tomcat

配置

web.xml

<web-app>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
            instead of the default XmlWebApplicationContext -->
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <!-- Again, config locations must consist of one or more comma- or space-delimited
            and fully-qualified @Configuration classes -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.acme.web.MvcConfig</param-value>
        </init-param>
    </servlet>

    <!-- map all requests for /app/* to the dispatcher servlet -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

ServletConfig.java

@Configuration
@ImportXml("classpath:app.xml")
@ComponentScan("com.acme")
public class ServletConfig {
    @Bean(primary=Primary.TRUE)
    public Service myService() {
        return new Service();
    }

    @Bean
    public Service backupService() {
        return new Service();
    }
}

分析

DispatcherServlet启动SpringMVC启动容器AnnotationConfigWebApplicationContext。

AnnotationConfigWebApplicationContext构造器中创建了一个AnnotatedBeanDefinitionReader。AnnotatedBeanDefinitionReader在注册的时候,会调用org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)。

AnnotationConfigUtils#registerAnnotationConfigProcessors方法中,注册了一个ConfigurationClassPostProcessor

在ApplicationContext调用refresh的时候,调用invokeBeanFactoryPostProcessors()的方法时候,会时候ConfigurationClassPostProcessor对加载进来的BeanDefinition进行解析(注意,这里是一定Spring已经加载的Bean)。

ConfigurationClassPostProcessor的@Configuration的解析。参考**@ComponentScan解析原理**

情况3-javaconfig + xml入口 + SpringMVC + external Tomcat

配置

web.xml

<web-app>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <!-- map all requests for /* to the dispatcher servlet -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

applicationContext.xml

<beans>
    <!-- enable processing of annotations such as @Autowired and @Configuration -->
    <!-- 选项1,配置自动扫描注解 -->
    <context:annotation-config/>
    
    <!-- 选项2,注册ConfigurationClassPostProcessor -->
    <bean class="org.springframework.context.annotation.ConfigurationClassPostProcessor"/>
    
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="com.acme.ServletConfig"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

ServletConfig.java

@Configuration
@ImportXml("classpath:app.xml")
@ComponentScan("com.acme")
public class ServletConfig {
    @Bean(primary=Primary.TRUE)
    public Service myService() {
        return new Service();
    }

    @Bean
    public Service backupService() {
        return new Service();
    }
}

分析

选项1,使用自动扫描注解配置,间接配置了ConfigurationClassPostProcessor

选项2,直接配置ConfigurationClassPostProcessor

其余和情况1,基本相同

情况4-SpringBoot + java config + embedded Tomcat

App.java

@SpringBootApplication
@Import(CoreAppConfig.class)
@PropertySource("classpath:application-mgsite.properties")
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

SpringApplication里面会创建AnnotationConfigServletWebServerApplicationContext容器。创建AnnotationConfigServletWebServerApplicationContext容器的时候。注册ConfigurationClassPostProcessor。同时注册ClassPathBeanDefinitionScanner。

同时注册主方法所在的类App.java。这样就能够解析其@Configuration注解。

参考SpringBoot启动容器