在web环境中使用spring框架的细节了解(方便理解之后的集成)

本文介绍如何将Spring容器与Web应用集成,通过监听Web应用启动加载Spring容器,并将其存储在ServletContext中,以便在整个Web应用中复用。同时讨论了如何忽略配置文件名和容器键名。

小结:

  1. 容器不再是每一次都要获取创建, 也就是说, spring的配置文件或者配置类不再需要被多次加载. 而是设计在web应用一启动就创建出app对象
  2. 可以忽略配置名, 也就说, 配置名不一样只需要去修改web.xml文件, 不用动源代码
  3. 可以隐藏app对象的键名(在域中)

spring与web环境的集成

现在pom.xml中导入jar包
一个是serlvet一个是jsp

		<dependency>
          <!--Servlet的jar包-->
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
      </dependency>
      <dependency>
          <!--jsp的jar包-->
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.1</version>
      </dependency>

当有了这两个包之后, 可以写web层的东西了
注意: 这里回顾一下什么是Mvc设计模式, 什么是软件开发的三层架构

此时存在的弊端

当写控制器代码时, 对于app这个对象的获取方式, 当业务一多时, 加载spring配置文件(或者是主配置类)的次数就会很多, 其实这是没有意义的, 其实loc容器只需要创建一次即可

解决方法

在web项目中, 可以使用ServletContextListener监听web应用的启动, 我们可以在web应用的启动时, 就加载spring的loc容器, 也即是app对象, 并将其存放到最大的域ServletContext中, 这样就可以在任意的位置获取app对象了

代码实例

/*
* 实现这个接口目的是为了监听当web应用启动时*/
public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        ServletContext servletContext = sce.getServletContext();
        servletContext.setAttribute("app",app);
        System.out.println("loc容器创建好了...");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

这里使用maven的tomcat插件run会报错, 要在idea中为这个项目配置本地tomcat来启动

E:\Tomcat\apache-tomcat-8.5.66\bin\catalina.bat run
[2021-12-20 12:28:39,234] Artifact lea:war exploded: Waiting for server connection to start artifact deployment...
Using CATALINA_BASE:   "C:\Users\LYD\.IntelliJIdea2018.3\system\tomcat\Unnamed_lea"
Using CATALINA_HOME:   "E:\Tomcat\apache-tomcat-8.5.66"
Using CATALINA_TMPDIR: "E:\Tomcat\apache-tomcat-8.5.66\temp"
Using JRE_HOME:        "C:\Java\jdk-13.0.2"
Using CLASSPATH:       "E:\Tomcat\apache-tomcat-8.5.66\bin\bootstrap.jar;E:\Tomcat\apache-tomcat-8.5.66\bin\tomcat-juli.jar"
Using CATALINA_OPTS:   ""
NOTE: Picked up JDK_JAVA_OPTIONS:  --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
20-Dec-2021 12:28:40.472 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Server.服务器版本: Apache Tomcat/8.5.66
20-Dec-2021 12:28:40.473 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 服务器构建:        May 8 2021 22:44:01 UTC
20-Dec-2021 12:28:40.474 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 服务器版本号:      8.5.66.0
20-Dec-2021 12:28:40.474 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 操作系统名称:      Windows 10
20-Dec-2021 12:28:40.474 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log OS.版本:           10.0
20-Dec-2021 12:28:40.475 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 架构:              amd64
20-Dec-2021 12:28:40.475 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Java 环境变量:     C:\Java\jdk-13.0.2
20-Dec-2021 12:28:40.475 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Java虚拟机版本:    13.0.2+8
20-Dec-2021 12:28:40.475 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log JVM.供应商:        Oracle Corporation
20-Dec-2021 12:28:40.475 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:     C:\Users\LYD\.IntelliJIdea2018.3\system\tomcat\Unnamed_lea
20-Dec-2021 12:28:40.475 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:     E:\Tomcat\apache-tomcat-8.5.66
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       --add-opens=java.base/java.lang=ALL-UNNAMED
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       --add-opens=java.base/java.io=ALL-UNNAMED
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       --add-opens=java.base/java.util=ALL-UNNAMED
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Djava.util.logging.config.file=C:\Users\LYD\.IntelliJIdea2018.3\system\tomcat\Unnamed_lea\conf\logging.properties
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dcom.sun.management.jmxremote=
20-Dec-2021 12:28:40.476 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dcom.sun.management.jmxremote.port=1099
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dcom.sun.management.jmxremote.ssl=false
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dcom.sun.management.jmxremote.authenticate=false
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Djava.rmi.server.hostname=127.0.0.1
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Djdk.tls.ephemeralDHKeySize=2048
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dignore.endorsed.dirs=
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dcatalina.base=C:\Users\LYD\.IntelliJIdea2018.3\system\tomcat\Unnamed_lea
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Dcatalina.home=E:\Tomcat\apache-tomcat-8.5.66
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Djava.io.tmpdir=E:\Tomcat\apache-tomcat-8.5.66\temp
20-Dec-2021 12:28:40.477 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent 使用APR版本[1.7.0]加载了基于APR的Apache Tomcat本机库[1.2.28]20-Dec-2021 12:28:40.478 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR功能:IPv6[true]、sendfile[true]、accept filters[false]、random[true]20-Dec-2021 12:28:40.478 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL配置:useAprConnector[false],useOpenSSL[true]
20-Dec-2021 12:28:40.481 信息 [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL成功初始化 [OpenSSL 1.1.1k  25 Mar 2021]
20-Dec-2021 12:28:40.529 信息 [main] org.apache.coyote.AbstractProtocol.init 初始化协议处理器 ["http-nio-8080"]
20-Dec-2021 12:28:40.831 信息 [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
20-Dec-2021 12:28:40.845 信息 [main] org.apache.catalina.startup.Catalina.load Initialization processed in 822 ms
20-Dec-2021 12:28:40.891 信息 [main] org.apache.catalina.core.StandardService.startInternal 正在启动服务[Catalina]
20-Dec-2021 12:28:40.892 信息 [main] org.apache.catalina.core.StandardEngine.startInternal 正在启动 Servlet 引擎:[Apache Tomcat/8.5.66]
20-Dec-2021 12:28:40.903 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["http-nio-8080"]
20-Dec-2021 12:28:40.915 信息 [main] org.apache.catalina.startup.Catalina.start Server startup in 68 ms
Connected to server
[2021-12-20 12:28:41,339] Artifact lea:war exploded: Artifact is being deployed, please wait...
20-Dec-2021 12:28:42.364 信息 [RMI TCP Connection(3)-127.0.0.1] org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
20-Dec-2021 12:28:42.595 信息 [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.support.AbstractApplicationContext.prepareRefresh Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@57765b41: startup date [Mon Dec 20 12:28:42 CST 2021]; root of context hierarchy
loc容器创建好了...
20-Dec-2021 12:28:43.416 警告 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom 使用[SHA1PRNG]创建会话ID生成的SecureRandom实例花费了[290]毫秒。
[2021-12-20 12:28:43,443] Artifact lea:war exploded: Artifact is deployed successfully
[2021-12-20 12:28:43,443] Artifact lea:war exploded: Deploy took 2,105 milliseconds
20-Dec-2021 12:28:50.905 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [E:\Tomcat\apache-tomcat-8.5.66\webapps\manager]
20-Dec-2021 12:28:50.946 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[E:\Tomcat\apache-tomcat-8.5.66\webapps\manager]的部署已在[41]毫秒内完成

使用ServletContext域中的app对象

@WebServlet("/saveUserServlet")
public class SaveUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        ApplicationContext app = (ApplicationContext)servletContext.getAttribute("app");
        UserService userService = (UserService)app.getBean("userService");
        userService.save();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

打开浏览器访问

http://localhost:8080/lea_war_exploded/saveUserServlet

控制台打印

20-Dec-2021 16:36:45.943 警告 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom 使用[SHA1PRNG]创建会话ID生成的SecureRandom实例花费了[294]毫秒。
[2021-12-20 04:36:45,965] Artifact lea:war exploded: Artifact is deployed successfully
[2021-12-20 04:36:45,965] Artifact lea:war exploded: Deploy took 5,504 milliseconds
20-Dec-2021 16:36:47.217 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [E:\Tomcat\apache-tomcat-8.5.66\webapps\manager]
20-Dec-2021 16:36:47.257 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[E:\Tomcat\apache-tomcat-8.5.66\webapps\manager]的部署已在[40]毫秒内完成
这是Orale的实现方法
调用了持久层的方法

万一有的人的项目的spring配置文件不叫applicationContext.xml或者说spring的主配置类不叫SpringConfiguration. 这时原代码中获取app的地方就要修改代码. 怎样可以让代码忽略spring的配置文件名或者主配置类名呢?

在web.xml中配置全局变量
例如

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--全局初始化变量-->
  <context-param>
    <param-name>contextConfiguration</param-name>
    <param-value>SpringConfiguration.class</param-value>
  </context-param>

  <!--配置监听器-->
  <listener>
    <listener-class>web.listener.ContextLoaderListener</listener-class>
  </listener>



</web-app>

小结 : 这里注意一个地方, 设置全局初始化变量只能在最上面, 不然会报错
然后修改一下监听器处的代码:

/*
* 实现这个接口目的是为了监听当web应用启动时*/
public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        
        ServletContext servletContext = sce.getServletContext();
        //读取参数
        String contextConfiguration = servletContext.getInitParameter("contextConfiguration");
        //利用全局变量来获取app对象, 就算spring配置的名称不一样, 只用修改web.xml
        ApplicationContext app = new AnnotationConfigApplicationContext(contextConfiguration);
        servletContext.setAttribute("app",app);
        System.out.println("loc容器创建好了...");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

这里再进一步考虑更细, 如果不知道存放进ServletContext域中的app的键名也就叫app呢?怎么样不用去记住这个键名?

写一个工具类

package utils;

import org.springframework.context.ApplicationContext;

import javax.servlet.ServletContext;

public class WebApplicationContextUtils {
    public static ApplicationContext getApp(ServletContext servletContext){
        return (ApplicationContext)servletContext.getAttribute("app");
    }
}

在用到app对象的地方修改代码

@WebServlet("/saveUserServlet")
public class SaveUserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        /*ApplicationContext app = (ApplicationContext)servletContext.getAttribute("app");*/
        //使用这个工具类就可以完全忽略域中app的键名
        ApplicationContext app = WebApplicationContextUtils.getApp(servletContext);
        UserService userService = (UserService)app.getBean("userService");
        userService.save();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值