Spring-集成Web

一、引子

前面我们在Spring集成Junit中为读者引出了Spring善于集成其它框架的优势,而Spring项目不可能仅限于小范围的某个方法的测试,终究会落脚于Web项目上。于是,我们就从这里正式进入Spring集成Web的话题。由于笔者会从原生的Java Web开发过渡到Spring集成Web,从而体现出Spring集成的魅力,因此在阅读这篇文章之前,希望读者已经有关于Java Web的一些基础(可先浏览Java Web专栏),包括Servlet,Tomcat,JSP等。

这里笔者想多说几句,虽然现在主流的开发似乎都不再与Servlet,Tomcat,JSP之流直接接触了,但是理解一个技术,是要理解这个技术为什么产生,是解决了当时的什么问题,这样能帮助我们将不断迭代的技术连贯起来,因此我们就需要了解这门技术产生之前使用的是什么技术,这样会让我们更深入地理解现在使用的技术的优势。Servlet是Web应用的基石,虽不直接使用却是必要掌握的;Tomcat(这里泛指Web服务器)似乎在SpringBoot的兴起后而不再需要像此前一样关注,但是Web项目离不开Tomcat;JSP更是一门难用、逐渐被摒弃的语言,虽然JSP是过时的技术,但依旧不妨去学习到能看懂JSP代码的程度,这样你将更能理解什么是前后端分离。重要的是,当你慢慢熟悉技术的迭代发展,你会对一些似乎耳熟能详的词语感觉到豁然开朗而不是"看似"理解了这些概念。

二、仅用Spring框架如何实现?

(1)利用我们上一篇介绍的Spring注解开发,声明一个配置类:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.bylearning")
public class SpringConfiguration {
}

(2)定义Dao层与Service层类,注解在类上添加注解,表明将此类交给Spring容器:

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    public void save() {
        System.out.println("save successfully...");
    }
}

Service层注入Dao层对象属性

import com.bylearning.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void saveUser() {
        userDao.save();
    }
}

Web层先延用在Java Web中使用的Servlet:

import com.bylearning.config.SpringConfiguration;
import com.bylearning.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/demo")
public class DemoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        ApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        UserService us = ioc.getBean(UserService.class);
        us.saveUser();
    }
}

配置Tomcat,启动项目,在浏览器地址栏中访问该Servlet便可在控制台中看到Dao层中打印的输出语句。至此便完成了原生的Spring 对于Web的开发。

三、在此基础上怎么改进?

我们注意到在DemoServlet类中,我们为了获取到容器中的Service层对象,利用配置类创建了一个IoC容器。我们不禁想到:难道每个Servlet中都要重复这一段代码吗,这不仅是代码的重复,可以想象更是性能的负担,我们不可能这么做。有经验的小伙伴可能会想到一个办法:提供一个静态方法来获取单例的IoC容器呗。例如这样:

import com.bylearning.config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IoCUtil {
    
    public static ApplicationContext ioc;
    
    static {
        ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    }
    
    public static ApplicationContext getIoC() {
        return ioc;
    }
}

但是我们根据Java类加载顺序知道,静态代码块会在类第一次被加载的时候自动执行,这意味着创建容器的耗时操作将落在第一次被访问的Servlet时,这似乎也不太优雅。

解决办法:还记得我们在介绍Java Web阶段简单提及的三大组件之一——Listener(回顾)。监听器中其中有一个ServletContextListener就是监听ServletContext对象的创建与销毁。因此我们在启动Web项目时,会自动执行该监听器的contextInitialized()方法。我们把创建容器的逻辑放在这个方法里很优雅了。

监听类中创建IoC容器:

import com.bylearning.config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ContextLoaderListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("listener init...");
        ApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        ServletContext servletContext = servletContextEvent.getServletContext();
        servletContext.setAttribute("ioc", ioc);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }

}

提供一个工具类:

import org.springframework.context.ApplicationContext;

import javax.servlet.ServletContext;

public class WebApplicationContextUtils {

    public static ApplicationContext getWebApplicationContext(ServletContext servletContext) {
        ApplicationContext ioc = (ApplicationContext) servletContext.getAttribute("ioc");
        return ioc;
    }
}

改造Servlet获取Service层对象:

import com.bylearning.WebApplicationContextUtils;
import com.bylearning.service.UserService;
import org.springframework.context.ApplicationContext;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/demo")
public class DemoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        ApplicationContext ioc = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        UserService us = ioc.getBean(UserService.class);
        us.saveUser();
    }
}
四、Spring为我们做好了——Spring集成Web

如此典型的优化动作,Spring作为一个优秀的框架,当然为我们做好了。于是我们要开始介绍Spring集成Web。

1、引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.1</version>
        </dependency>

2、使用spring-web依赖中提供的工具类。我们此时删除import,重新引入时发现了两个工具类供我们选择,一个是我们在上一步中自己实现的,下一个是spring-web提供的。我们选择下面那一个。

3、在web.xml里配置监听类。不用我们自己在定义监听类了,只需要在web.xml里配置好,并将Spring配置文件作为全局参数配置好。前面我们特意设计将我们自定义的监听类与spring-web提供的监听类名称一致。

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

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

4、Spring配置文件。进行包扫描即可

<?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 https://www.springframework.org/schema/context/spring-context.xsd">

    <!--扫描控制层组件-->
    <context:component-scan base-package="com.bylearning"/>

</beans>
五、总结

至此,我们便完成了Spring集成Web的介绍,我们可以看到我们只需要完成监听器的配置与初始参数的配置,接着就可以利用工具类获取到IoC容器了。接下来,我们将为读者继续介绍SpringMVC的内容。

读者在阅读第三、四节时可能会有一个疑问:这里为什么是用一个Servlet来充当Web层呢,这和当下流行的Controller是什么关系呢?因为我们是从原生的Java Web开发过渡而来,因此采用在Java Web开发中常用的继承HttpServlet接口来承接客户端请求,下面我们将为读者介绍SpringMVC的内容,这将与大家熟知的Controller联系起来,请读者继续阅读SpringMVC-基本概念

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值