3.Spring5底层原理之ApplicationContext实现.md
这一章我们来看看创建ApplicationContext的几种方法。
首先我们创建一个类进行测试,内容如下:
public class A02Application {
public static void main(String[] args) {
testClassPathXmlApplicationContext();
}
// 较为经典的容器,基于classpath下xml格式的配置文件来创建
private static void testClassPathXmlApplicationContext(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml");
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
static class Bean1{
}
static class Bean2{
private Bean1 bean1;
public void setBean1(Bean1 bean1){
this.bean1 = bean1;
}
public Bean1 getBean1(){
return bean1;
}
}
}
A02Application类中,有Bean1,Bean2两个类,Bean2依赖Bean1。
基于classpath下xml格式的配置文件来创建
testClassPathXmlApplicationContext()方法测试利用xml进行创建ApplicationContext,这是一种很经典的用法,但是现在基本上很少用了,我们在resources下创建Spring的配置文件b01.xml,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.zhaojun.springsource.a02.A02Application$Bean1" id="bean1"/>
<bean class="com.zhaojun.springsource.a02.A02Application$Bean2" id="bean2">
<property name="bean1" ref="bean1"/>
</bean>
</beans>
相信以前用xml配置spring的同学应该明白上面的配置是什么意思。就是定义了两个bean,分别是bean1和bean2,其中bean2依赖bean1。
我们运行main方法,调用testClassPathXmlApplicationContext,输出结果如下
10:37:51.207 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2a70a3d8
10:37:51.485 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [b01.xml]
10:37:51.516 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
10:37:51.528 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
bean1
bean2
com.zhaojun.springsource.a02.A02Application$Bean1@2af004b
从日志中可以看到,ClassPathXmlApplicationContext从b01.xml中加载了两个bean定义,然后创建了两个Bean
基于磁盘路径下xml格式的配置文件来创建
不仅可以基于classpath下xml来创建,不在classpath下呢,可以用FileSystemXmlApplicationContext来创建
// 基于磁盘路径下xml格式的配置文件来创建
private static void testFileSystemXmlApplicationContext(){
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/b01.xml");
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
和classpath差不多,只不过就是换了加载路径,这里就不过多赘述了。
基于java配置类来创建
首先我们在A02Application中创建一个配置类
@Configuration
static class Config{
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1){
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
然后创建AnnotationConfigApplicationContext
// 较为经典的容器,基于java配置类来创建
private static void testAnnotationConfigApplicationContext(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
输出日志
11:28:42.872 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@543c6f6d
11:28:42.890 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
11:28:42.992 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
11:28:42.993 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
11:28:42.995 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
11:28:42.996 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
11:28:43.003 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a02Application.Config'
11:28:43.008 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
11:28:43.019 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
11:28:43.021 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'bean2' via factory method to bean named 'bean1'
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
a02Application.Config
bean1
bean2
com.zhaojun.springsource.a02.A02Application$Bean1@431cd9b2
Process finished with exit code 0
可以看到,利用AnnotationConfigApplicationContext会帮我们创建后处理器,在上一章我们讲过,后处理器能帮我们处理注解来创建bean。
基于java配置类来创建,用于web环境
// 较为经典的容器,基于java配置类来创建,用于web环境
private static void testAnnotationConfigServletWebServer() {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
我们还需要一个WebConfig
@Configuration
static class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1(){
return new Controller() {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().println("hello");
return null;
}
};
}
}
首先需要一个web容器,我们创建内嵌的tomcat容器,然后我们知道springmvc的入口是DispatcherServlet,然后我们把DispatcherServlet注册到web容器上,“/”表示对所有请求进行处理。
最后,我们创建一个Controller,用来实验我们是否创建成功。运行main方法。查看日志
12:54:09.033 [main] DEBUG org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext - Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@3578436e
12:54:09.090 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
12:54:09.195 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
12:54:09.197 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
12:54:09.198 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
12:54:09.199 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
12:54:09.205 [main] DEBUG org.springframework.ui.context.support.UiApplicationContextUtils - Unable to locate ThemeSource with name 'themeSource': using default [org.springframework.ui.context.support.ResourceBundleThemeSource@4b520ea8]
12:54:09.206 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'servletWebServerFactory'
12:54:09.207 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a02Application.WebConfig'
12:54:10.164 [main] DEBUG org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory - Code archive: D:\repository\org\springframework\boot\spring-boot\2.6.4\spring-boot-2.6.4.jar
12:54:10.164 [main] DEBUG org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory - Code archive: D:\repository\org\springframework\boot\spring-boot\2.6.4\spring-boot-2.6.4.jar
12:54:10.164 [main] DEBUG org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory - None of the document roots [src/main/webapp, public, static] point to a directory and will be ignored.
12:54:10.216 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
4月 15, 2022 12:54:10 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
4月 15, 2022 12:54:10 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
4月 15, 2022 12:54:10 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.58]
4月 15, 2022 12:54:10 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring embedded WebApplicationContext
12:54:10.415 [main] DEBUG org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
12:54:10.415 [main] INFO org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1383 ms
12:54:10.418 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'dispatcherServletRegistrationBean'
12:54:10.421 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'dispatcherServlet'
12:54:10.446 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'dispatcherServletRegistrationBean' via factory method to bean named 'dispatcherServlet'
12:54:10.458 [main] DEBUG org.springframework.boot.web.servlet.ServletContextInitializerBeans - Mapping filters:
12:54:10.458 [main] DEBUG org.springframework.boot.web.servlet.ServletContextInitializerBeans - Mapping servlets: dispatcherServlet urls=[/]
12:54:10.475 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean '/hello'
12:54:10.491 [main] DEBUG org.springframework.context.support.DefaultLifecycleProcessor - Starting beans in phase 2147483646
4月 15, 2022 12:54:10 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
12:54:10.513 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
12:54:10.514 [main] DEBUG org.springframework.context.support.DefaultLifecycleProcessor - Successfully started bean 'webServerStartStop'
12:54:10.515 [main] DEBUG org.springframework.context.support.DefaultLifecycleProcessor - Starting beans in phase 2147483647
12:54:10.515 [main] DEBUG org.springframework.context.support.DefaultLifecycleProcessor - Successfully started bean 'webServerGracefulShutdown'
通过日志我们可以发现,在8080端口,启动了一个web服务,我们访问http://localhost:8080/hello。效果如下图:
总结
本章我们了解了ApplicationContext常见的四种实现。