Servlet与SrpingMvc

205 阅读3分钟

ServletContainerInitializer

Shared libraries(共享库) and runtimes pluggability(运行时插件)的原理,在后面的框架整合里,用得比较多,来分析下它

ServletContainerInitializer在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filters等,servlet规范(JSR356)中通过ServletContainerInitializer实现此功能。

每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类,那么,当web容器启动时就会运行这个初始化器做一些组件内的初始化工作。

如下:

@HandlesTypes(value = SamService.class)//感兴趣的类
public class SamServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        System.out.println("感兴趣的类型");
        for (Class<?> clazz : set) {
            System.out.println(clazz);// 反射
        }

        ServletRegistration.Dynamic orderServlet = servletContext.addServlet("orderServlet", new OrderServlet());
        orderServlet.addMapping("/order");

        servletContext.addListener(OrderListener.class);

        FilterRegistration.Dynamic orderFilter = servletContext.addFilter("orderFilter", OrderFilter.class);
        orderFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

    }
}

在springMVC中的使用:

我们可以通过依赖发现SpringMvc也使用了这么一种方式,

image-20200520155659933

我们打开可以看到里买呢额内容是:

org.springframework.web.SpringServletContainerInitializer

所以在我我们的容器启动的时候就会执行者们一个类

打开WebApplicationInitializer源码看看组件及实现

子类AbstractContextLoaderInitializer作用:

子类AbstractDispatcherServletInitializer的作用:从名字来看可知是DispatcherServlet初始化

子类AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的dispatcherServlet初始化器

root根容器与servlet容器的区别在哪呢?父子容器

很明显,servlet的容器用来处理@Controller,视图解析,和web相关组件

而root根容器主要针对服务层,和数据源DAO层及事务控制相关处理(图源自spring官网)

SpringMVC流程整合

新建类继承AbstractAnnotationConfigDispatcherServletInitializer类

public class SamWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  //获取根容器的配置类;(Spring的配置文件)   父容器;
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SamRootConfig.class};
    }
	//获取web容器的配置类(SpringMVC配置文件)  子容器;
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SamApplicationConfig.class};
    }
	//获取DispatcherServlet的映射信息
	//  /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
	//  /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

新建两个配置类模拟根容器和web容器

@ComponentScan(value = "com.enjoy", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = true)
public class SamRootConfig {
}
@ComponentScan(value = "com.enjoy",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class})
},useDefaultFilters = false)
@EnableWebMvc
public class SamApplicationConfig implements WebMvcConfigurer {
//实现webMvcConfigurer可以自定义一些SpringMVC功能
		
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/pages/",".jsp");
    }

    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
		
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SamInterceptor()).addPathPatterns("/*");
    }
}

新建Controller与Service

@Service
public class OrderService {
    public String goBuy(String orderId) {
        return "orderId====" + orderId;
    }
}
@Controller
public class OrderController {
    @Autowired
    OrderService orderService;

    @ResponseBody
    @RequestMapping("/buy")
    public String buy() {
        return orderService.goBuy("12345678");
    }

    //相当于会找 /WEB-INF/pages/ok.jsp
    @RequestMapping("/ok")
    public String ok() {
        return "ok";
    }
}

Servlet异步请求

同步请求

image-20200520154541218
同步请求的原理

从tomcat中获取连接线程进行处理,但tomcat的线程数有限,会造成线程资源的紧张。

image-20200520154649649

异步请求

image-20200520154819183

Servlet实现异步请求的方式

@WebServlet(value = "/asyncOrder", asyncSupported = true)
public class OrderAsyncServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("主线程开始……" + Thread.currentThread() + "start....." + System.currentTimeMillis());

        AsyncContext asyncContext = req.startAsync();

        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                System.out.println("副线程开始……" + Thread.currentThread() + "start....." + System.currentTimeMillis());

                try {
                    buyCards();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                asyncContext.complete();
                ServletResponse response = asyncContext.getResponse();
                try {
                    response.getWriter().write("order successful");
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println("副线程结束……" + Thread.currentThread() + "end....." + System.currentTimeMillis());


            }
        });

        System.out.println("主线程结束……" + Thread.currentThread() + "end....." + System.currentTimeMillis());
    }

    public void buyCards() throws InterruptedException {
        System.out.println(Thread.currentThread() + ".............");
        Thread.sleep(5000);//模拟业务操作
    }
}

SpringMvc中的异步请求

  • Callable
@Controller
public class AsyncOrderController {

    @ResponseBody
    @RequestMapping("/orderCallable")
    public Callable<String> callOrder() {
        System.out.println("主线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
        Callable<String> callable = new Callable<String>() {

            public String call() throws Exception {
                System.out.println("副线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("副线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
                return "order buy successful........";
            }
        };
        System.out.println("主线程结束..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
        return callable;
    }
}
  • DeferredResult
@Controller
public class AsyncUserController {

    @Autowired
    UserService userService;

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(20);
    private ExecutorService threadPool;

    @PostConstruct
    public void startThreadPool() {
        threadPool = new ThreadPoolExecutor(CPU_COUNT * 2, CPU_COUNT * 2, 60L, TimeUnit.SECONDS, queue);
    }

    @RequestMapping(value = "/login")
    @ResponseBody
    public DeferredResult<String> login(final String name) {
        System.out.println("主线程开始..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
        final DeferredResult<String> deferredResult = new DeferredResult<String>(10000L, "----failed-------");
        threadPool.execute(new Runnable() {
            public void run() {
                try {
                    Random r = new Random();
                    userService.login(name, r.nextInt(5000), deferredResult);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println("主线程结束..." + Thread.currentThread() + "==>" + System.currentTimeMillis());
        return deferredResult;

    }

}

手写SpringMvc

github