Spring、SpringMVC及Web容器分析

Spring 容器

  • Spring容器是什么?

Spring容器是Spring的核心,Spring容器是管理bean对象的地方,其通过IoC技术管理。Spring容器也就是一个bean工厂(BeanFactory)。应用中bean的实例化,获取,销毁等都是由这个bean工厂管理的。更进一步讲,spring容器是管理service和dao的容器.

  • Spring容器究竟是什么?

Spring提供两种容器类型:BeanFactory和ApplicationContext

  • BeanFactory:基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IoC容器选择。
  • ApplicationContext:ApplicationContext:在BeanFactory的基础上构建,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等,这些会在后面详述。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。

在普通的JAVA工程中,我们可以通过代码显式new一个ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext来初始化一个Spring容器。

在Web工程中,我们一般是通过配置web.xml的方式来初始化Spring容器。

  • 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”  
       xsi:schemaLocation=”http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans.xsd”>  
  
  <bean id=“…” class=“…”>  
    <!– collaborators and configuration for this bean go here >  
  </bean>  
  
  <bean id=“…” class=“…”>  
    <!– collaborators and configuration for this bean go here >  
  </bean>  
  
  <!– more bean definitions go here >  
  
</beans>  
  • 通过ClassPathApplicationContext初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

我们写这一句简单的代码,其实Spring在里面做了很多功夫。
首先Spring会从classpath路径下找到services.xml和daos.xml文件,
然后将文件内的配置信息读取出来,
然后做了N多内部的初始化工作。

  • 我们还可以用FileSystemApplicationContext来初始化Spring容器
ApplicationContext context = new FileSystemXmlApplicationContext("D:/Test/services.xml");

这2中方式效果是一样的,只是通过不同的方式读取配置文件。
容器初始完后,我们就可以用这个容器来获取我们之前配置了个bean,简单示例如下:

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

// retrieve configured instance
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);

// use configured instance
List userList = service.getUsernameList();
<strong>
<span style="font-family:Microsoft YaHei;"></span></strong>
  • Web工程的Spring配置
my-app
–src
—-resources
——services.xml
–WebContent
—-META-INF
—-WEB-INFI
——lib
——applicationContext.xml
——web.xml

那么我们的web.xml需要这么,配置方式如下:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml classpath:resources/services.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  • contextConfigLocation:

contextConfigLocation指的是Spring该去哪里读取配置文件,ContextLoaderListener用于启动的web容器(如tomcat)时,去读取配置文件并完成Spring容器的初始化(包括加载bean等)。
关于contextConfigLocation的配置方式也是可以非常丰富的,还可以使用通配符 * ,这里简单举几个例子说明:

  1. classpath:resources/services.xml表示到web工程的classes/resources文件夹中查找配置文件。
  2. classpath*:resources/services.xml这种方式除了会到classes/resources文件夹查找,还会到lib下面的jar包中查找,查找路径是jar包内/resources/services.xml。
  3. classpath:resouces/**/*services.xml这种方式表示到classpath的resources文件夹下所有文件夹(不限层级,可以在第N层子文件夹中)中查找文件名以services.xml结尾的文件。
  4. 多个路径配置可以用空格分开
  • classpath知识补充:

web工程部署后,对应war包下的WEB-INF下会有一个classes文件夹和一个lib文件,当然还有其他的。
其中classes文件夹中的内容是从工程中的源码文件夹(对应右键工程,Properties - Java Build Path - Source页签中看到的文件夹)中编译过来,lib文件夹即工程中引用的jar包。
这个classes文件夹和lib中的jar都属于classpath。

  • ContextLoaderListener:

这个Listener就是在标准Spring Web工程中Spring开始干活的切入点,为什么要说标准?因为我们可以写一个自己的Listener去启动Spring容器。扯远了~
因为ContextLoaderListener实现了ServletContextListener,所以在web容器启动时,ContextLoaderListener就悄悄开始工作了,至于怎么工作的还需要点篇幅去描述,这篇文件就先不细说。

Spring MVC容器

  • 什么是Spring MVC容器

SpringMVC是管理bean对象的地方,更进一步的讲,pringMVC是管理controller的容器。其次,spring容器和springMVC容器是父子容器的关系,spring容器是父容器,springMVC是子容器,而子容器可以访问父容器中的对象,父容器却不能访问子容器对象。通俗点就是,controller可以访问service对象,service不能访问controller对象。

  • Spring和Spring MVC的关系及区别

Spring是根容器,SpringMVC是其子容器。子容器的创建依赖于父容器的创建,父容器先于子容器创建。子容器(SpringMVC容器)可以访问父容器(Spring容器)的Bean,父容器(Spring容器)不能访问子容器(SpringMVC容器)的Bean。也就是说,当在SpringMVC容器中getBean时,如果在自己的容器中找不到对应的bean,则会去父容器中去找,这也解释了为什么由SpringMVC容器创建的Controller可以获取到Spring容器创建的Service组件的原因。
ContextLoaderListener中创建Spring容器主要用于整个Web应用程序需要共享的一些组件,比如DAO、数据库的ConnectionFactory等;而由DispatcherServlet创建的SpringMVC的容器主要用于和该Servlet相关的一些组件,比如Controller、ViewResovler等。在实际工程中,一个项目中会包括很多配置,根据不同的业务模块来划分,我们一般思路是:Spring根容器负责所有其他非controller的Bean的注册,而SpringMVC只负责controller相关的Bean的注册。

  • spring-mvc.xml
<context:component-scan base-package="com.smart.controller" />

applicationContext-service.xml

<!-- 扫描包加载Service实现类 -->
    <context:component-scan base-package="com.smart.service"></context:component-scan> or
    <context:component-scan base-package="com.smart">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
  • SpringMVC的拦截器也是springmvc容器管理的,所以在springmvc的拦截器里,可以直接注入bean对象
<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/employee/**" ></mvc:mapping>
            <bean class="com.smart.core.shiro.LoginInterceptor" ></bean>
        </mvc:interceptor>
    </mvc:interceptors>

Web容器

  • 什么是Web容器了

web容器是管理servlet,以及监听器(Listener)和过滤器(Filter)的。 这些都是在web容器的掌控范围里。但他们不在spring和springmvc的掌控范围里 。因此,我们无法在这些类中直接使用Spring注解的方式来注入我们需要的对象,是无效的,
web容器是无法识别的。
但我们有时候又确实会有这样的需求,比如在容器启动的时候,做一些验证或者初始化操作,这时可能会在监听器里用到bean对象;又或者需要定义一个过滤器做一些拦截操作,也可能会用到bean对象

  • Web容器如何获取Spring的bean对象呢?下面我提供两个方法:
public void contextInitialized(ServletContextEvent sce) {
  ApplicationContext context = (ApplicationContext) sce.getServletContext().getAttribute(
  WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); 
  UserService userService = (UserService) context.getBean("userService");
}
public void contextInitialized(ServletContextEvent sce) {
  WebApplicationContext webApplicationContext =WebApplicationContextUtils.
  getWebApplicationContext(sce.getServletContext()); 
  UserService userService = (UserService) webApplicationContext.getBean("userService"); 
}

注意 :以上代码有一个前提, 那就是servlet容器在实例化ConfigListener并调用其方法之前,要确保spring容器已经初始化完毕 !而spring容器的初始化也是由Listener(ContextLoaderListener)完成,因此只需在web.xml中先配置初始化spring容器的Listener,然后在配置自己的Listener。

参考资料

[^1 ] Spring容器是什么
[^2] 《Spring揭秘》笔记——Spring中两种容器比较
[^3] spring容器和springmvc容器,以及web容器的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值