servlet 3.0注解开发
servlet 3.0可以直接使用注解开发Java web项目,不需要配置web.xml
。
/**
访问/hello可以看到hello,不需要配置其他
*/
@WebServlet("/hello")
public class hello extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("hello");
}
}
ServletContainerInitializer
-
servlet 3.0规定 servlet 容器启动时会扫描当前应用里面的每一个 jar 包的
ServletContainerInitializer
的实现,启动并运行这个实现类的方法 -
提供
ServletContainerInitializer
的实现类,这个实现类必须绑定在META-INF/service/javax.servlet.ServletContainerInitializer
,文件的内容就是实现类的全类名
/**
程序启动时会运行该接口的实现类的onStartup()方法
ServletContext var2:代表当前web应用的ServletContext对象
*/
public interface ServletContainerInitializer {
void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException;
}
Set<Class<?>> set
/**
*自定义的实现类:set的栗子
* 容器启动时,将@HandlesTypes指定的类型下面的子类(子接口、子类)传递过来,本类不会传递
* Set<Class<?>> set:就是这些传递过来的类/接口的集合
*/
@HandlesTypes({helloService.class})
public class MyServletContainerInitialize implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("遍历set");
for (Class<?> obj : set)
{
System.out.println(obj);
}
}
}
详细操作:
-
image.png
-
image.png
ServletContext
注册三大组件
在项目启动的时候利用ServletContext
注册第三方组件/自己写的组件:servlet
listener
filter
调用参数servletContext
的addxxx
方法即可
有两处地方可以使用ServletContext
注册组件:
-
ServletContainerInitializer
(就是上面讲的) - 在
listener
里可以使用,因为监听器也是在项目启动时候创建,运行时是注册不了(/≧▽≦)/
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
}
}
Servlet 3.0 整合Spring mvc

由servlet3.0 可知,容器启动的时候会自动扫描当前应用里面的每一个 jar 包的
ServletContainerInitializer
的实现,启动并运行这个实现类的方法,上面是spring web实现的类
/**
* 应用一启动就会去加载 WebApplicationInitializer下的所有子类,创建对象(也就是组件,除去子接口、抽象
* 类)
*/
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
......
}
/**
* WebApplicationInitializer的子类
*/
public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer
{
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//注册ContextLoaderListener
registerContextLoaderListener(servletContext);
}
protected void registerContextLoaderListener(ServletContext servletContext) {
//创建根容器
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
}
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
//注册DispatcherServlet
this.registerDispatcherServlet(servletContext);
}
protected void registerDispatcherServlet(ServletContext servletContext) {
.......
//创建一个Web的ioc容器
WebApplicationContext servletAppContext = this.createServletApplicationContext();
......
//创建一个dispatcherServlet
FrameworkServlet dispatcherServlet = this.createDispatcherServlet(servletAppContext);
//将dispatcherServlet添加到servletContext
dispatcherServlet.setContextInitializers(this.getServletApplicationContextInitializers());
Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. Check if there is another servlet registered under the same name.");
} else {
//配置dispatcherServle信息,通过类似getServletMappings()我们可以配置
registration.setLoadOnStartup(1);
registration.addMapping(this.getServletMappings());
registration.setAsyncSupported(this.isAsyncSupported());
Filter[] filters = this.getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
Filter[] var7 = filters;
int var8 = filters.length;
for(int var9 = 0; var9 < var8; ++var9) {
Filter filter = var7[var9];
this.registerServletFilter(servletContext, filter);
}
}
this.customizeRegistration(registration);
}
}
}
/**
* 注解方式配置DispatcherServlet初始化器
*/
public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer {
//重写父类AbstractDispatcherServletInitializer的方法
protected WebApplicationContext createRootApplicationContext() {
//这里传入的配置类
Class<?>[] configClasses = this.getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
} else {
return null;
}
}
//依旧是重写,创建web的ioc容器
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
//获取配置类
Class<?>[] configClasses = this.getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
context.register(configClasses);
}
return context;
}
}
总结
以注解方式启动spring mvc
,需要继承AbstractAnnotationConfigDispatcherServletInitializer
,实现该类的抽象方法指定DispatcherServlet
的配置信息
两个容器的关系

实例:
spring
基本的 jar 包还是要导入,spring-webmvc
也需要导入,使用 tomcat 启动就可以了
package com.xixi.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
//Spring容器不扫描controller,父容器
@ComponentScan(value = "com.xixi",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})
public class RootConfig {
}
package com.xixi.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
//spring mvc容器只扫描controller,子容器,需要禁用默认规则
@ComponentScan(value = "com.xixi", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class WebConfig {
}
package com.xixi;
import com.xixi.config.RootConfig;
import com.xixi.config.WebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 以前spring mvc两个配置文件,现在配置文件只是变成了配置类
* @return
*/
@Override
//创建根容器配置类(spring 配置文件)
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
//获取web容器配置类(spring mvc的配置文件)
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
//获取DispatchServlet的映射路径
protected String[] getServletMappings() {
//拦截所有请求(包括静态资源),除了*.jsp
return new String[]{"/"};
}
}

定制、接管Spring mvc
- 开启spring mvc 定制配置功能
@EnableWebMvc
=== ><mvc:annotation-driver/>
- 实现
WebMvcConfigurer
,配置组件(视图解析器、视图映射、静态资源映射、拦截器.....),需要什么实现即可
官方文档介绍
image.png
网友评论