springmvc源码-注解启动

Servlet 介绍

Servlet是sun公司提供的一门用于开发动态web资源的技术。
  Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
  1、编写一个Java类,实现servlet接口。
  2、把开发好的Java类部署到web服务器中。
  按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet

Servlet 和 SpringMVC的关系

SpringMVC是基于Servlet封装的MVC框架

Servlet线程是否安全?如何证明
答:在Servlet 的无参构造函数上面输出内容,并且在该Servlet类上设置变量,在请求的方法上输出并修改变量。
在这里插入图片描述结果: Servlet线程是不安全的,所以是需要注意线程安全问题。解决方法: doGet方法上加锁、变量上加上原子类。

使用注解代替之前的web.xml配置

原理的xml方式

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.kaico.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

使用注解方式,使用 @WebServlet() 注解,注解参数为请求路径。

@WebServlet("/")
public class MyServlet extends HttpServlet {
    private Integer count = 0;

    public MyServlet() {
        System.out.println("<<<MyServlet被实例化...>>>");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        count++;
        try {
            Thread.sleep(50);
        } catch (Exception e) {
        }
        resp.getWriter().print(" this is mayikt  count:" + count);
    }
}

ServletContainerInitializer 接口

在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。
每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类。

1、Servlet容器启动会扫描,当前应用里面每一个jar包的 ServletContainerInitializer的实现
2、提供ServletContainerInitializer的实现类;必须绑定在,META-INF/services/javax.servlet.ServletContainerInitializer文件的内容就是ServletContainerInitializer实现类的全类名;

@HandlesTypes(value = MyHandlesType.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {

    /**
     * @param set            感兴趣类型 也就是MyHandlesType 所有子类型
     * @param servletContext
     * @throws ServletException
     */
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        // 1.打印所有感兴趣的类型
        for (Class<?> c : set) {
            System.out.println(c);
        }
        // 2.servletContext 手动注册过滤器、servlet、监听器
        ServletRegistration.Dynamic payServlet = servletContext.addServlet("payServlet", new PayServlet());
        payServlet.addMapping("/pay");
    }
}

在这里插入图片描述
想使用这个接口的实现类的话,必须增加这个配置文件,这是定义的规范。

注解启动 SpringMVC

1、启动 SpringMVC容器类注入到Spring中
2、注入我们的springMVC的配置文件
3、将我们的DispatcherServlet注入到servlet容器中。
4、填写url路径的映射

项目启动时使用 tomcat 启动。

项目结构如图所示:webapp中的配置文件应该全部删除,使用 java 类来配置。
Java配置类,作用:增加mvc开关、配置扫包范围
在这里插入图片描述继承了 WebApplicationInitializer 接口的类,这里配置 servlet并且绑定 url 路径
在这里插入图片描述springmvc没有web.xml配置文件时如何启动的?
首先查看源码(如下图)得知:继承了WebApplicationInitializer接口的类会传递到SpringServletContainerInitializer类中方法onStartUp 中。
在这里插入图片描述在这里插入图片描述原理:Sevlet容器在初始化的时候会加载到这个SpringServletContainerlnitializer,然后找HandlesTypes子类 传回调传递servletContext。

配置视图层

配置类SpringMvcConfig 中增加这个方法,注入bean InternalResourceViewResolver
在这里插入图片描述

拦截器和过滤器

相同点:拦截器和过滤器都是基于AOP技术实现,对方法实现增强,都可以拦截请求方法。
不同点:
1.过滤器属于Servlet自己研发的,而拦截器技术属于SpringMVC自己研发的。
2.过滤器属于拦截Web请求,而拦截器不仅可以拦截请求还可以拦截普通方法。
3.过滤器会比拦截器先执行,拦截器封装的方法比过滤器拦截使用起来更加简单。

实际开发中绝大多数情况下,都会使用拦截器
拦截器:权限控制、日志打印、参数验证、会话。
过滤器应用场景:编码转换、跨域解决、xss攻击。

拦截器的代码写法:实现接口
在这里插入图片描述注入到Spring中,配置类实现 WebMvcCondfigurer接口,将拦截器bean添加,在配置类SpringMvcConfig 中增加下面代码添加拦截器
在这里插入图片描述注意:使用拦截器一定要关闭EnableWebMvc 否则拦截器不会生效。

SpringMVC多线程异步处理

为什么使用多线程?提高我们的响应的速度、异步执行。

在我们的Web 中为什么要使用异步呢?
目的:快速响应给客户端,防止客户端请求等待的。.单独开启一个线程处理。
使用异步也有缺点:线程安全问题、不能及时拿到结果、消耗CPU。

注解使用异步

在方法上使用注解:@Async
在这里插入图片描述controller层调用 service 层这个方法的时候,使用异步线程执行。

可以配置线程池

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 线程池的配置
 */
@Configuration
public class AsyncConfig {

    private static final int MAX_POOL_SIZE = 50;

    private static final int CORE_POOL_SIZE = 20;

    @Bean("asyncTaskExecutor")
    public AsyncTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
        asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-");
        asyncTaskExecutor.initialize();
        return asyncTaskExecutor;
    }
}

配置好后,@Async会默认从线程池获取线程,当然也可以显式的指定@Async(“asyncTaskExecutor”)

Callable 接口实现异步

使用 Callable 实现异步需要设置asyncSupported 为true开启异步
在这里插入图片描述使用方式如下:
在这里插入图片描述这里会等待 callable 里面的方法执行完成之后,才会返回给客户端。service 层的方法去掉注解 @Async 。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值