Spring ----------- spring and the Web

preface

To use the Spring framework in a web project, we must first solve the problem of obtaining the Spring container in the web layer (here referred to as Servlet).
As long as the Spring container is obtained in the web layer, the Service object can be obtained from the container.

1, Problems of using Spring in Web projects

Example: Spring web project (modified on the basis of spring mybatis)

Create a Maven Project

Select the project prototype Maven archetype webapp

Copy original project code

Copy the following from the spring mybatis project to the current project:

(1) All codes of Service layer and Dao layer
(2) Configuration file ApplicationContext XML and JDBC properties,mybatis.xml
(3)pom.xml
(4) Add servlet and jsp dependency

In the previous POM Add the following contents to the XML file:

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.2.1-b03</version>
  <scope>provided</scope>
</dependency>

If it is tomcat10, replace the first one with

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>5.0.0</version>
    <scope>provided</scope>
</dependency>

Define index interface

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
    <form action="RegisterServlet" method="get">
        full name: <input type="text" name="name"> <br>
        Age: <input type="text" name="age"> <br>
             <input type="submit" value="register">
    </form>
</body>
</html>

Define RegisterServlet

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String strName = request.getParameter("name");
    String strAge = request.getParameter("age");
    
    String config = "applicationContext.xml";
    ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
    System.out.println("Container information:" + ctx);
    StudentService service = (StudentService) ctx.getBean("studentService");

    Student student = new Student();
    student.setName(strName);
    student.setAge(Integer.parseInt(strAge));
    
    service.addStudent(student);
    
    request.getRequestDispatcher("/result.jsp").forward(request, response);
}

Define the result interface

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
     <h1>login was successful</h1>
</body>
</html>

web.xml registration Servlet

<servlet>
    <servlet-name>RegisterServlet</servlet-name>
    <servlet-class>com.fancy.controller.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>RegisterServlet</servlet-name>
    <url-pattern>/RegisterServlet</url-pattern>
</servlet-mapping>

Operation result analysis

When the form is submitted, jump to success JSP, refresh the page several times, check the background output, and find that every time the page is refreshed, a new Spring container will be created. That is, each time a request is submitted, a new Spring container is created. For an application, only one Spring container is needed. Therefore, it is problematic to put the creation statement of Spring container in the doGet() or doPost() method of Servlet.


At this point, you can consider creating the Spring container when the Servlet is initialized, that is, when the init() method is executed. Moreover, servlets are single instance multithreaded, that is, a service has only one Servlet instance, and all users executing the service execute this Servlet instance. In this way, the Spring container is unique.
However, a Servlet is a business and a Servlet instance, that is, there is only one LoginServlet, but there will also be StudentServlet, TeacherServlet, etc. Each business will have a Servlet, execute its own init() method, and create a Spring container. In this way, the Spring container is not unique.

2, Use Spring's listener ContextLoaderListener

For Web applications, the ServletContext object is unique. For a Web application, there is only one ServletContext object, which is initialized when the Web application is loaded. If the creation time of Spring container is put at the initialization of ServletContext, it can ensure that the creation of Spring container will be executed only once, which ensures the uniqueness of Spring container in the whole application.

After the Spring container is created, it should be accessible at any time during the whole application life cycle. That is, the Spring container should be global. The attributes put into the ServletContext object have the global nature of the application. Therefore, putting the created Spring container into the ServletContext space in the form of attributes ensures the globality of the Spring container.

maven relies on POM xml

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>5.2.5.RELEASE</version>
</dependency>

Register listener ContextLoaderListener

To create a Spring container when the ServletContext is initialized, you need to use the listener interface ServletContextListener to listen to the ServletContext. On the web Register the listener in XML.

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Spring defines an implementation class ContextLoaderListener for the listener interface, which completes two very important tasks: creating a container object and putting the container object into the space of ServletContext.

Open the source code of ContextLoaderListener. There are four methods in total. Two are construction methods, one is initialization method, and the other is destruction method.

Tracing the initWebApplicationContext() method, you can see that the container object is created in it.


Moreover, the created container object is put into the space of ServletContext, and the key is a constant: webapplicationcontext ROOT_ WEB_ APPLICATION_ CONTEXT_ ATTRIBUTE.

Specify the location of the Spring configuration file < context param >

When ContextLoaderListener creates a Spring container, it needs to load the Spring configuration file. The default Spring configuration file location and name is: WEB-INF / ApplicationContext xml. However, the configuration file is usually placed under the classpath of the project, that is, src, so it needs to be on the web Specify the location and name of the Spring configuration file in XML.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

From the source code of the parent class ContextLoader of the listener ContextLoaderListener, you can see the location parameter name contextConfigLocation of the configuration file to be read.

Get Spring container object

There are two common ways to get container objects in servlets

(1) Get directly from ServletContext

According to the source code analysis of the listener ContextLoaderListener, the key stored in the servlet context of the container object is webapplicationcontext ROOT_ WEB_ APPLICATION_ CONTEXT_ ATTRIBUTE. Therefore, you can directly obtain the container object according to the specified key through the getAttribute() method of ServletContext.

String attr = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
WebApplicationContext ac = (WebApplicationContext)this.getServletContext().getContext(attr);

(2) Get through WebApplicationContextUtils

The tool class WebApplicationContextUtils has a method specifically used to obtain the Spring container object from the ServletContext: getRequiredWebApplicationContext(ServletContext sc)

Call the method provided by Spring to obtain the container object:

WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());

No matter which of the above two methods is used to obtain the container object, after refreshing the success page, you can see that the Spring container used in the code is the same object.

Keywords: Java Front-end Spring

Added by dc277 on Sat, 12 Feb 2022 12:51:21 +0200