Entrevistador: ¡Cuénteme sobre el proceso de inicio de Spring MVC!

Inserte la descripción de la imagen aquí

Contenedor y especificación de servlet

Nuestro Spring MVC de uso común se implementa en función de la especificación de Servlet, así que revisemos primero el contenido relacionado con Servlet.

Inserte la descripción de la imagen aquí

Si usamos directamente Servlet para desarrollar aplicaciones web, solo necesitamos heredar HttpServlet e implementar el método de servicio. HttpServlet hereda de Servlet. Los métodos comúnmente usados ​​en Servlet son los siguientes

public interface Servlet {
    
    

	// 初始化,只会被调用一次,在service方法调用之前完成
    void init(ServletConfig config) throws ServletException;
    
    ServletConfig getServletConfig();
    
    // 处理请求
    void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
    
    String getServletInfo();
    
    // 销毁
    void destroy();
}

Cada Servlet tiene un ServletConfig, que se utiliza para almacenar la configuración relacionada con el Servlet.
Cada aplicación Web tiene un ServletContext, que se utiliza para almacenar la configuración relacionada con el contenedor.

Teniendo en cuenta que muchos socios pequeños pueden no estar familiarizados con muchos usos de Servlet, vamos a presentarlo brevemente y usar la configuración xml. Por supuesto, puede usar JavaConfig para cambiarlo

La estructura del proyecto es la siguiente
Inserte la descripción de la imagen aquí

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
          http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

  <context-param>
    <param-name>configLocation</param-name>
    <param-value>test</param-value>
  </context-param>

  <servlet>
    <servlet-name>userServlet</servlet-name>
    <servlet-class>com.javashitang.controller.UserServlet</servlet-class>
    <init-param>
      <param-name>helloWord</param-name>
      <param-value>hello sir</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>userServlet</servlet-name>
    <url-pattern>/user.do</url-pattern>
  </servlet-mapping>

  <listener>
    <listener-class>com.javashitang.listener.MyServletContextListener</listener-class>
  </listener>

</web-app>
public class UserServlet extends HttpServlet {
    
    

    private String helloWord;

    @Override
    public void init(ServletConfig config) throws ServletException {
    
    
        this.helloWord = config.getInitParameter("helloWord");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        String userId = req.getParameter("userId");
        out.println(helloWord + " " + userId);
    }
}

En el archivo de configuración xml, puede usar la etiqueta init-param para establecer algunas configuraciones para el Servlet, y luego usar ServletConfig en el método init para obtener estas configuraciones y realizar la inicialización

访问
http://localhost:8080/user.do?userId=1
返回
hello sir 1

Puede ver que también hemos configurado la etiqueta de carga al inicio para este servlet, entonces, ¿cuál es el uso de esta etiqueta?

Load-on-startup significa que el servlet se inicializa cuando se inicia el contenedor. Cuanto más pequeña sea la matriz, mayor será la prioridad de inicio. Cuando esta etiqueta no está configurada, el servlet se inicializará cuando llegue la primera solicitud.

La etiqueta context-param es la configuración inicial del contenedor, puede llamar al método getInitParameter del contenedor para obtener el valor del atributo

Listener es un mecanismo de extensión que envía varios eventos cuando la aplicación web se inicia o se detiene. Podemos usar Listener para monitorear estos eventos y hacer un trabajo de inicialización. Como monitorear el evento de inicio para inicializar la conexión de la base de datos, etc.

Mi demostración acaba de obtener la ubicación del archivo de configuración y lo imprimió.

public class MyServletContextListener implements ServletContextListener {
    
    

	// 容器启动
    public void contextInitialized(ServletContextEvent sce) {
    
    
        ServletContext sc = sce.getServletContext();
        String location = sc.getInitParameter("configLocation");
        System.out.println(location);
    }

	// 容器销毁
    public void contextDestroyed(ServletContextEvent sce) {
    
    

    }
}

Escribe una aplicación Spring MVC

Escribimos una aplicación Spring MVC basada en xml, y analizamos en base a esta aplicación. La estructura del proyecto es la siguiente:
Inserte la descripción de la imagen aquí
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
          http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
		 version="3.1">
		 
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-context.xml</param-value>
	</context-param>

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

	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

spring-context.xml (servicio de configuración, capa dao)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<context:component-scan base-package="com.javashitang.service"/>

</beans>

spring-mvc.xml (configuración y configuración relacionada con spring mvc)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<context:component-scan base-package="com.javashitang.controller"/>
	<mvc:annotation-driven/>

</beans>
@RestController
public class UserController implements ApplicationContextAware {
    
    

	@Resource
	private UserService userService;
	private ApplicationContext context;

	@RequestMapping("user")
	public String index(@RequestParam("userId") String userId) {
    
    
		return userService.getUsername(userId);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
		this.context = applicationContext;
		System.out.println("UserController " + context.getId());
	}
}
public interface UserService {
    
    

	String getUsername(String userId);
}
@Service
public class UserServiceImpl implements UserService, ApplicationContextAware {
    
    

	private ApplicationContext context;

	@Override
	public String getUsername(String userId) {
    
    
		return userId;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
		this.context = applicationContext;
		System.out.println("UserServiceImpl " + context.getId());
	}
}

La razón por la que necesitamos usar 2 archivos de configuración es porque hay 2 contenedores en Spring MVC

El contenedor primario es inicializado por el ContextLoaderListener, generalmente utiliza para almacenar alguna capa capa DAO y el servicio de haba
sub-contenedores se inicializan por DispatcherServlet, que se utiliza generalmente para almacenar la capa del controlador de la haba

Se puede ver en el valor impreso después de que se inicia el proyecto que el Servicio y el Controlador se obtienen de 2 contenedores

UserServiceImpl org.springframework.web.context.WebApplicationContext:
UserController org.springframework.web.context.WebApplicationContext:/dispatcher

El contenedor secundario puede acceder al Bean del contenedor principal y el contenedor principal no puede acceder al Bean del contenedor secundario. Cuando no se puede encontrar el Bean correspondiente en el contenedor secundario, se encontrará en el contenedor principal.

Inicio del contenedor principal

ContextLoaderListener inicializa el contenedor principal. Cuando se inicia Tomcat, publica el evento de inicio, llama al método ContextLoaderListener # contextInitialized y luego llama al método initWebApplicationContext

Inserte la descripción de la imagen aquí

Inicio contenedor infantil

El inicio del subcontenedor está en el método DispatcherServlet # init

DispatcherServlet no anuló el método init, por lo que está en la clase principal. HttpServletBean anula el método init.
Inserte la descripción de la imagen aquí
Resuma el proceso con un diagrama de flujo

Inserte la descripción de la imagen aquí
Si cree que el contenedor principal es inútil, puede poner todos los frijoles en el contenedor secundario

Blog de referencia

Supongo que te gusta

Origin blog.csdn.net/zzti_erlie/article/details/115190719
Recomendado
Clasificación