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启动容器