美文网首页
servlet3.0 与 spring web

servlet3.0 与 spring web

作者: 林嘻嘻呀 | 来源:发表于2020-05-16 15:34 被阅读0次

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

  1. servlet 3.0规定 servlet 容器启动时会扫描当前应用里面的每一个 jar 包的ServletContainerInitializer的实现,启动并运行这个实现类的方法

  2. 提供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
调用参数servletContextaddxxx方法即可
有两处地方可以使用ServletContext注册组件:

  1. ServletContainerInitializer(就是上面讲的)
  2. 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

image.png
由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的配置信息
两个容器的关系

image.png
实例:
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[]{"/"};
    }
}
image.png

定制、接管Spring mvc

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

相关文章

网友评论

      本文标题:servlet3.0 与 spring web

      本文链接:https://www.haomeiwen.com/subject/wqznnhtx.html