我们之前将所有的容器创建过程都放在了一个配置文件中(一个配置文件中整合了SpringMVC、Mybatis等等)这样做太凌乱了。如果有一个过程出错了,整个容器都会出错,这时就引入了父子容器,在启动的时候先启动除了Controller以外的所有的其他的类型对象,而在真正Servlet启动的时候只把Controller和Intercepter加载出来就行了。(所有的Handle都是Spring体系下的东西)
Controller层属于Spring体系,Service层属于SpringMVC体系
@Service,@Repository,@Autowired这些注解在没有SpringMVC的体系下都可以单独存在,这种可以单独存在的如果和SpringMVC配置在一个配置文件中就比较凌乱了。SpringMVC应该有他自己的容器,Spring有他自己的容器。Spring用来管理Mybatis,SpringMVC。
真正启动一个SpringMVC项目的时候第一件事应该是启动一个Listener(监听器,只负责监听,不干遇项目的执行)。这Listener监听全局事务,当某个事务发生时会触发他的回调。Servlet是当某个请求发生时会触发他的回调。Filter是当一个请求过来时,他会在Servlet之前触发回调,并且决定Servlet是否执行
Listener的配置
<web-app>
<display-name>Archetype Created Web Applicationdisplay-name>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>springservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-*.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
这时项目的启动顺序变为:先启动applicationContext容器,然后再启动spirng-mvc容器(原来是一口大锅,现在是鸳鸯锅了)
接下来把我们之前创建的那一口大锅整理一下。
原来的模样
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.lanou">context:component-scan>
<mvc:annotation-driven>mvc:annotation-driven>
<mvc:resources mapping="/static/**" location="/static/">mvc:resources>
<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="com.mysql.cj.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://localhost:3306/db_zbmanager?serverTimezone">property>
<property name="username" value="root">property>
<property name="password" value="zaq991221">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="mapperLocations" value="classpath:mapper/*.xml">property>
bean>
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.lanou.mapper">property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
beans>
整理后的模样
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<context:component-scan base-package="com.lanou">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
context:component-scan>
<bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="com.mysql.cj.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://localhost:3306/db_zbmanager?serverTimezone">property>
<property name="username" value="root">property>
<property name="password" value="zaq991221">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="mapperLocations" value="classpath:mapper/*.xml">property>
bean>
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.lanou.mapper">property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
beans>
spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<context:component-scan base-package="com.lanou.controller">context:component-scan>
<mvc:annotation-driven>mvc:annotation-driven>
<mvc:resources mapping="/static/**" location="/static/">mvc:resources>
beans>
这样项目启动的时候就会将大部分类的创建扔到了父容器中,而子容器还没有启动。当一个访问来子容器才启动,子容器的Controller才创建出来(只需要创建Controller就行了,别的东西就不会再创建了)
这样容器启动的过程会变慢一点,但是运行速度会变快。
这里需要注意一下,如果子容器扫描一个包,父容器也扫描相同的包,或者子容器创建一套数据库链接,父容器也创建一套数据库链接。这样会出大问题,父容器的事务链接过程会被子容器覆盖,同时覆盖掉原来在父容器中声明好的可以使用的事务管理过程,这时候事务就不会生效了。所以不要把在父容器中声明过的对象在子容器中在声明一遍,父子容器一定要把活分清。子容器就启动SpringMVC体系需要的东西,父容器加载为子容器服务的所有组件。
日志系统应该放在父容器中,但是刚才我们整理的父容器放的都是和数据库有关的东西,我不想把日志系统加进去,怎么办?稍微改一下之前的配置
web.xml
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext*.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
创建一个applicationContext*.xml文件,将日志系统和AOP过程放到这里。
注意:这里的applicationContext.xml和applicationContext-log.xml是一个容器,他们和spring-mvc之间是两个容器。(listener启动了父容器,servlet启动了子容器)