servlet

servlet

package com.itheima.demo;

import javax.servlet.*;
import java.io.IOException;

public class MySelvert implements Servlet {
    public MySelvert() {
        System.out.println("MyServlet方法执行了");
    }
  private   ServletConfig servletConfig;//将该变量提升为成员变量
    @Override
    //一般在这里做一些初始化的准备工作,比如读取配置文件    默认在浏览器第一次请求时,servlet创建好之后只调用一次。
    public void init(ServletConfig servletConfig) throws ServletException {
       // System.out.println("init方法调用了");
    }

    @Override
    //对外提供服务的核心方法(接受请求,处理请求做出响应),具体的业务逻辑写在这里。每次请求都会执行
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
       // System.out.println("service方法调用了");
        //获取初始化的值
        String username = servletConfig.getInitParameter("username");
        String password = servletConfig.getInitParameter("password");
        // System.out.println("username+"=="+password");
        System.out.println(username);
        System.out.println(password);
    }

    @Override
    //当服务器正常关闭的时候,服务器销毁servlet 对象之前调用,一般在这个里面做一些善后收尾工作。服务器关闭之后就调用了。
    public void destroy() {
        System.out.println("destroy方法调用了");
    }

    @Override
    //获取配置对象
    public ServletConfig getServletConfig() {
        return this.servletConfig;
    }

    @Override
    //获取作者的版本信息,不用做任何业务逻辑,但是必须存在
    public String getServletInfo() {
        return null;
    }


}
  <!--一个servlet可以配置多个映射路径,一个路径不可以对应多个servlet,映射路径可以是多级的。-->
   <!-- <servlet>
        <servlet-name>myservlet</servlet-name>
        <servlet-class>com.itheima.demo.MySelvert</servlet-class>-->
        <!--配置初始化参数-->
        <!--<init-param>
            <param-name>username</param-name>
            <param-value>cherry</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>123</param-value>
        </init-param>-->
        <!--配置加载时期,只能在配置初始化参数之后使用-->
       <!-- <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>myservlet</servlet-name>
        <url-pattern>/demo1</url-pattern>
    </servlet-mapping>-->

servlet 实现用户的注册

@WebServlet("/demo2")
public class MyServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username1 = req.getParameter("username1");
        String password1 = req.getParameter("password1");
        //实现注册功能代码
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url="jdbc:mysql://localhost:3306/mydb2";
            String username="root";
        String password="123456";
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        String sql="insert into user1(name,password) values(?,?)";
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            preparedStatement.setString(1,username1);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            preparedStatement.setString(2,password1);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        int i = 0;
        try {
            i = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        if(i>0){
            System.out.println("注册成功");
        }else{
            System.out.println("注册失败");
        }


    }


    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    this.doPost(req, resp);
    }
}
index,jsp
<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2020/10/16
  Time: 10:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
<form action="http://localhost:8080//demo2" method="post">
  用户名:<input type="text" name="username1">
  <br>
  密码:<input type="text" name="password1">
  <br>
  <input type="submit" value="提交">
</form>
  </body>
</html>

servlet是单例多线程

Servlet如何处理多个请求访问?

servlet容器是默认采用单例多线程的方式处理多个请求的:

  1. 当web服务器启动的时候或者说客户端发送请求到服务端的时候,servlet就被加载并实例化(只存在一个servlet实例);
  2. 容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。
  3. 当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
  4. 线程执行Servlet的service方法;
  5. 请求结束,放回线程池,等待被调用;
    (注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题)

结论:

  1. Servlet单实例,减少了产生servlet的开销;
  2. 通过线程池来响应多个请求,提高了请求的响应时间;
  3. Servlet容器并不关心到达的Servlet请求访问的是否是同一个Servlet还是另一个Servlet,直接分配给它一个新的线程;如果是同一个Servlet的多个请求,那么Servlet的service方法将在多线程中并发的执行;
  4. 每一个请求由ServletRequest对象来接受请求,由ServletResponse对象来响应该请求;

Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题。

JSP中存在的多线程问题:

当客户端第一次请求某一个JSP文件时,服务端把该JSP编译成一个CLASS文件,并创建一个该类的实例,然后创建一个线程处理CLIENT端的请求。如果有多个客户端同时请求该JSP文件,则服务端会创建多个线程。每个客户端请求对应一个线程。以多线程方式执行可大大降低对系统的资源需求,提高系统的并发量及响应时间.

JSP中遇到的变量

实例变量:实例变量是在堆中分配的,并被属于该实例的所有线程共享,所以线程不是安全的。

JSP系统中提供的8个类变量

JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是线程安全的(因为每个线程对应的request,respone对象都是不一样的,不存在共享问题), APPLICATION在整个系统内被使用,所以不是线程安全的.

局部变量:局部变量在堆栈中分配,因为每个线程都有它自己的堆栈空间,所以是线程安全的。

静态类:静态类不用被实例化,就可以直接使用,也不是线程安全的。

外部资源:在程序中可能会有多个线程或者进程同时操作同一个资源(如:多个线程或者进程同时对一个文件进行读写操作),这个时候也是要注意同步问题

客户端请求是以串行方式执行,这样会降低系统的性能,

Servlet容器如何同时来处理多个请求

Java的内存模型JMM(Java Memory Model)
JMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有实例变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。根据JMM,我们可以将论文中所讨论的Servlet实例的内存模型抽象为图所示的模型。

工作者线程Work Thread:执行代码的一组线程。

调度线程Dispatcher Thread:每个线程都具有分配给它的线程优先级,线程是根据优先级调度执行的。

Servlet采用多线程来处理多个请求同时访问。servlet依赖于一个线程池来服务请求。线程池实际上是一系列的工作者线程集合。Servlet使用一个调度线程来管理工作者线程。

当容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的service方法。当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet.当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行。
Servlet容器默认采用单实例多线程的方式来处理请求,这样减少产生Servlet实例的开销,提升了对请求的响应时间,对于Tomcat可以在server.xml中通过元素设置线程池中线程的数目。

就实现来说:
调度者线程类所担负的责任如其名字,该类的责任是调度线程,只需要利用自己的属性完成自己的责任。所以该类是承担了责任的,并且该类的责任又集中到唯一的单体对象中。而其他对象又依赖于该特定对象所承担的责任,我们就需要得到该特定对象。那该类就是一个单例模式的实现了。

注意:服务器可以使用多个实例来处理请求,代替单个实例的请求排队带来的效益问题。服务器创建一个Servlet类的多个Servlet实例组成的实例池,对于每个请求分配Servlet实例进行响应处理,之后放回到实例池中等待下此请求。这样就造成并发访问的问题。
此时,局部变量(字段)也是安全的,但对于全局变量和共享数据是不安全的,需要进行同步处理。而对于这样多实例的情况SingleThreadModel接口并不能解决并发访问问题。 SingleThreadModel接口在servlet规范中已经被废弃了。

Servlet容器的主要任务就是管理Servlet的生命周期;
Web容器也称之为web服务器,主要任务就是管理和部署web应用的;
应用服务器的功能非常强大,不仅可以管理和部署web应用,也可以部署EJB应用,实现容器管理的事务等等。。。
所以:Servlet容器<Web容器<应用服务器
Web服务器就是跟基于HTTP的请求打交道,而EJB容器更多是跟数据库,事务管理等服务接口交互,所以应用服务器的功能是很多的。

常见的web服务器就是Tomcat,但Tomcat同样也是Servlet服务器;

常见的应用服务器有WebLogic,WebSphere,但都是收费的;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值