Spring4MVC(四)整合Spring

1、是否需要进行Spring和SpringMVC的整合?

       其实SpringMVC是Spring的一部分,它已经是运行在Spring容器中的,既然如此,还有必要进行Spring和SpringMVC的整合吗在实际开发中,基本上都是会进行整合的,至少我还没看到过没有进行整合的。那么整合操作是必须的吗?答案是否定的。

1.1 需要整合

       一般都是会进行两者的整合,因为,类似于数据源,事务,整合其他框架(比如MyBatis)都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中)。实际上放入 Spring 配置文件对应的 IOC 容器中的还有 Service 和 Dao。所以不应该把这么的事情都交给SpringMVC来完成。

1.2 不需要整合

       其实也可以把所有的配置信息,都放在 SpringMVC 的配置文件中;也可以分多个 Spring 的配置文件,然后使用 import 节点导入其他的配置文件(或者在web.xml中配置DispatchServlet的时候,使用通配符指定配置文件的名称)。

      但是,这种方式不推荐,这也不是Spring的初衷。

2、Spring整合SpringMVC

创建一个新的工程SpringMVC_Spring,演示Spring和SpringMVC的整合;

2.1 创建web工程SpringMVC_Spring

创建工程(IDEA创建web工程的方式可以参考第一篇SpringMVC的文章),导入jar包:

jar包不需要这么全,只要有最重要的几个包就可以了,这里是展示了所有的包

2.2 配置Spring的监听器和SpringMVC的servlet

在web.xml中配置Spring的监听器和SpringMVC的servlet:

<?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_4_0.xsd"
         version="4.0">
    
    <!--配置Spring IOC 容器的 Listener-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext*.xml</param-value>
    </context-param>

    <!--配置SpringMVC的核心:DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <!-- 配置 DispatcherServlet 的一个初始化参数: 配置 SpringMVC 配置文件的位置和名称 -->
            <!--
                实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.
                默认的配置文件为: /WEB-INF/<servlet-name>-servlet.xml
            -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc*.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
</web-app>

web.xml中,使用了通配符的方式来指定配置文件的名称以及位置:

<param-value>classpath*:spring/applicationContext*.xml</param-value>


<param-value>classpath*:spring/springmvc*.xml</param-value>

这样就会去classpath下面去找spring目录下的以applicationContext开头和以springmvc开头的配置文件。

2.3 创建Spring和SpringMVC的配置文件

2.3.1 创建Spring的配置文件

       在项目的classpath下面创建目录spring,然后在该目录下创建applicationContext-mvc.xml(因为我们使用了通配符,所以这个命名也是可以的):

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--配置包扫描,扫描@Repository @Service
        排除掉@Controller,把它交给SpringMVC去管理-->
    <context:component-scan base-package="com.springmvc"></context:component-scan>


</beans>

2.3.2 创建SpringMVC的配置文件

        在项目的目录spring下创建springmvc-spring.xml(因为我们使用了通配符,所以这个命名也是可以的):

<?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-4.0.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <!-- 配置扫描的包,扫描@Controller和@ControllerAdvice注解 -->
    <context:component-scan base-package="com.springmvc"></context:component-scan>

    <mvc:annotation-driven />

    <!-- 配置视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

3、处理器和业务层编写

3.1 创建业务层Service

在src下面新建包com.springmvc(配置文件中扫描的包路径),下面新建一个TestService

package com.springmvc;

import org.springframework.stereotype.Service;

@Service
public class TestService {

    //这个构造方法只是为了显示该类被创建了几次
    public TestService(){
        System.out.println("TestService创建了。。。");
    }

    public String getName(){
        return "Spring";
    }
}

3.2 创建处理器Controller

在包com.springmvc(配置文件中扫描的包路径),下面新建一个TestController

package com.springmvc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("springmvc")
public class TestController {

    //这个构造方法只是为了显示该类被创建了几次
    public TestController() {
        System.out.println("TestController被创建了。。。");
    }

    @Autowired
    private TestService testService;

    @RequestMapping("testSpring")
    public ModelAndView testSpring(){
        String name = testService.getName();
        ModelAndView modelAndView = new ModelAndView("success");
        modelAndView.addObject("name",name);
        return modelAndView;
    }
}

4、前台页面编写

4.1 首页添加超链接

<a href="${pageContext.request.contextPath}/springmvc/testSpring">点击获取名称</a>

4.2 创建一个成功页面success.jsp

       因为我们的TestController中,请求处理成功,在ModelAndView中设置了名称为success的视图,所以需要在WEB-INF的views目录下面创建success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>成功页面</title>
  </head>
  <body>
  <h2>SUCCESS PAGE</h2>
  Hello  ${name}
  </body>
</html>

5、存在的问题分析

存在的问题:同一个Bean被初始化了两次。

5.1 演示上面的效果

启动项目,在首页点击超链接,页面跳转到success.jsp页面,效果如下:

咋一看,我们发现整合是成功的啊,但是我们查看控制台的打印如下:

       这是什么情况,这是在项目启动的时候,我们的处理器和业务类都被初始化了两次啊。因为Spring和SpringMVC都有自己的容器,而且需要注意的是,我们的TestController和TestService都是放在包com.springmvc下面的,并且我们在Spring和SpringMVC的配置文件中,配置的扫描包的路径也都是:com.springmvc

这样就导致:初始化Spring的IOC容器的时候和初始化SpringMVC的IOC容器时,都把这两个类给初始化了。

5.2 解决Bean重复初始化

5.2.1 不要重复扫描

       因为之前我们的Handler和Service都是放在同一个包下,这样配置包扫描的时候,就会把该包下面所有的都扫描了。因此我们可以把TestController放到com.springmvc.controller包下,把TestService放到com.springmvc.service包下,配置文件中的包扫描也是各自扫描给自的包:

<!-- 配置扫描的包,扫描@Controller和@ControllerAdvice注解 -->
    <context:component-scan base-package="com.springmvc.controller"></context:component-scan>
<!--配置包扫描,扫描@Repository @Service-->
<context:component-scan base-package="com.springmvc.service"></context:component-scan>

5.2.2 配置包扫描的时候排除掉某些注解不扫描

       5.2.1 的方法虽然也可以解决问题,但是这样也有不便的地方。因为在分模块开发的时候,每个模块下面都有Controller和Service,这样的话,就导致扫描路径不是很好去区分的。

       我们可以在<context:component-scan>标签里面使用两个子标签:<context:include-filter>和<context:exclude-filter>来进行更细化的配置,可以指定扫描的注解和不扫描的注解。

       在SpringMVC的配置文件中,可以使用<context:include-filter>来指定 只扫描注解:@Controller和@ControllerAdvice

use-default-filters="false" 这个别忘记改成false,就是不使用默认的扫描规则,默认会扫描所有的注解

<?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-4.0.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

     <!-- 配置扫描的包,只会扫描除@Controller和@ControllerAdvice注解、
         use-default-filters="false" 这个别忘记改成false,就是不使用默认的扫描规则,默认会扫描所有的注解-->
    <context:component-scan base-package="com.springmvc" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

    <mvc:annotation-driven />

    <!-- 配置视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

在Spring的配置文件中,可以使用<context:exclude-filter>来指定不扫描注解:@Controller和@ControllerAdvice

use-default-filters="false" 这个别忘记改成false,就是不使用默认的扫描规则,默认会扫描所有的注解

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--配置包扫描,扫描@Repository @Service
        排除掉@Controller和@ControllerAdvice,把它交给SpringMVC去管理-->
    <context:component-scan base-package="com.springmvc" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>


</beans>

6、SpringMVC的IOC容器和Spring的IOC容器的关系 

       servlet:代表的的容器为spring-mvc的子容器,而DispatcherServlet 是前端控制器,该容器专门为前端监听请求的时候所用,就是说当接收到url请求的时候会引用springmvc容器内的对象来处理。

       context-param:代表的容器是spring本身的容器,spring-mvc可以理解为一个继承自该容器的子容器,spring容器是最顶层的父类容器,跟java的继承原理一样

       SpringMVC 的 IOC 容器中的 bean 可以引用Spring IOC 容器中的 bean;反之, Spring IOC 容器中的bean则不能引用Spring MVC IOC容器中的 bean 。因为:Spring MVC IOC容器是Spring IOC容器的子类,子类可以引用父类,父类不能引用子类。

       从软件层面上来说,Spring MVC是展示层可以调用业务层,业务层不能调用展示层。

      当服务器解析web.xml的时候由于listener监听的原因,会优先初始化spring容器,之后才初始化spring-mvc容器。

       Spring MVC WEB 层容器可作为 “业务层” Spring容器的子容器:即 WEB 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器的 Bean(也就是说不能在Service或Dao中注入Controller)。

       注意:当Spring的IOC容器和SpringMVC的IOC容器的扫描包,可以扫描到相同的Controller和Service的时候,并且没有使用<context:exclude-filter>来排除某个注解的时候,Spring的IOC容器是可以访问SpringMVC的IOC容器中的Bean的(也就是可以在Service或Dao中引用Controller(使用注解@Autowired注入))。但是正式环境中,一般不会出现SpringMVC和Spring重复初始化同一个类的情况,所以不要在service和dao中注入Controller。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值