Tomcat servlet 区别?
2021-05-26 23:34:04
Tomcat servlet 区别?
servlet是一个接口,Tomcat是一个servlet实现类。同理 Jetty也会实现 Servlet接口。
就像是 jdbc一样,Mysql ,Oracle 都会进行实现。
接口是一种规范,一种标注,仅此而已。
使用内嵌Tomcat servlet
(1)、web.xml 太老旧,不建议。
(2)、@WebServlet 注释,封装的看不到内部代码了,不建议。
(3)、Tomcat api(推荐,可以手动模拟真正的流程)
SpringBoot创建Tomcat容器
创建
启动
SpringMVC内嵌Tomcat启动
只要有类的地方,一定会对类创建对象。
创建ContextLoaderListener
创建DispatcherServlet
关于 Root 与 Servlet
详情请点击官方文档
DispatcherServlet期望对其自身的配置WebApplicationContext进行扩展(plain的扩展 ApplicationContext)。WebApplicationContext有一个链接 ServletContext和Servlet与它相关联。它也与ServletContext 应用程序绑定在一起,以便应用程序可以使用静态方法RequestContextUtils来查找 WebApplicationContext是否需要访问它。
对于许多应用程序来说,拥有一个WebApplicationContext简单而且足够。也可能具有上下文层次结构,其中一个根WebApplicationContext 在多个DispatcherServlet(或其他Servlet)实例之间共享
,每个实例都有其自己的子WebApplicationContext配置。有关上下文层次结构功能的更多信息,请参见的其他ApplicationContext功能。
根WebApplicationContext通常包含需要在多个Servlet实例之间共享的基础结构Bean,例如数据存储库和业务服务。这些Bean被有效地继承,并且可以在Servlet特定的子级中重写(即重新声明),该子级WebApplicationContext通常包含给定本地的Bean Servlet。下图显示了这种关系:
从以上关系可以得知,若 Controller 中不加入 @Controller 注解,则会浏览器访问不到,URL 映射不到方法。
从而报错:(此案例就是 Controller 层使用 @Service 代替 @Controller)
因为会找不到对应的ViewResolver、HandlerMapping,箭头关系是向下。例如:若标注了 @Service 就会把 Bean 放入 Root里面,那么它就失去了 ViewResolver、HandlerMapping 的能力。反过来说,只有标注了 @Controller,那么它才会拥有 ViewResolver、HandlerMapping 的能力。
总结:Controller 类必须标注有 @Controller,Service层则标注只要是 @Component 使 @Resource 能够引用到即可。
另外,在 @Service 层也可以使用 @Resource 引用到 Controller Bean。但这样做并不好。
Xml上下文 与 注解上下文
初始化有没有加载Bean?
(1)ClassPathXmlApplicationContext xml = new ClassPathXmlApplicationContext("xxx.xml");
有。因为有调用 refresh() 方法。在构造器中调用
(2)AnnotationConfigWebApplicationContext anno = new AnnotationConfigWebApplicationContext();
没有。因为没有调用 refresh() 方法
注解替换 xml
自己来创建 DispatcherServlet,自己来添加 servlet。
官网注解替换 xml
1 | public class MyWebApplicationInitializer implements WebApplicationInitializer { |
1 | <web-app> |
Java SPI
可以加载 /META- INF/services/ 下面的类。
tomcat SPI
Tomcat在启动的时候,加载的工程所有目录(引用jar下的所有目录),加载 /META- INF/services/javax. xxx.xxx。
例如:下面会创建 SpringServletContainerInitializer 类。而它又实现了接口 ServletContainerInitializer 重写了 onStartup方法,则就会调用onStartup方法。就像是线程,实现 Runnable 接口重写 run方法,执行 run 方法一样。
当我们创建对象 SpringServletContainerInitializer,实现了接口 ServletContainerInitializer,重写了 onStartup方法,在调用 onStartup方法之前,发现在这个类上有注解 @HandlesTypes(WebApplicationInitializer.class)
@HandlesTypes:就是为了收集感兴趣的类。比如说:@HandlesTypes(WebApplicationInitializer.class) 注解,有 A、B、C三个类实现了 WebApplicationInitializer 接口,那么就会获取到 A、B、C三个类,并作为 onStartup 方法的第一个参数 @Nullable Set<Class<?>> webAppInitializerClasses。
此时,就会调用到我们自己的实现类的 onStartup 方法(因为我们实现了 WebApplicationInitializer 接口,会被感兴趣的类收集到)
1 | public class MyWebApplicationInitializer implements WebApplicationInitializer { |
总结:Tomcat在启动的时候,加载的工程所有目录(引用jar下的所有目录),加载 /META- INF/services/javax. xxx.xxx。
并创建对象,调用 onStartup 方法,它上面有 @HandlesTypes(WebApplicationInitializer.class) 感兴趣的类收集器会收集到我们的类。
从而感兴趣的类作为第一个参数,循环(反射创建对象,并调用 onStartup 方法)。调用到我们的 MyWebApplicationInitializer.onStartup 方法。
Springboot SPI
再讲述一遍。
/META-INF/spring.factories 文件,加载类。
把上面的串一下
SpringBoot.run 方法是为了启动 Tomcat,并启动(在上面我们已经分析到)。
Tomcat启动时,会有SPI机制,调用所有实现 WebApplicationInitializer 接口的 onStartup 方法(此时就会有 Servlet)。
SpringBootApplication注解为了实现自动装配,会有SPI机制,加载所有的 auto configuration。
自己 new Tomcat();
消息转换失败
来,让我们做一步,让它访问出错
添加消息转换器
消息转换器原理
因为子类 DelegatingWebMvcConfiguration 上有加注解 @Configuration,所以父类可以使用 @Bean 创建 Bean。
1 | @Configuration(proxyBeanMethods = false) |
此时,就会调用我们自定义配置类的 configureMessageConverters 方法
2021-05-27 16:50:06 暂记那么多。