从头开始
好多Web开发者都没有从头开始部署过SSM框架,网上一些教程总是加了一堆 常用但不是必须 的配置
本文旨在最少配置和依赖的情况下,构建起一个基于SpringMVC+Spring+MyBatis的Maven工程。
基于Maven的Web工程
当我们新建一个空的Maven工程的时候,仅有一个pom文件,一个source目录,一个resource目录,参考Java工程目录文章
加入Web目录
此时我们要使得这个工程变成Web工程,所以在source和resource同级的地方加入webapp目录
1 | ---main |
其中根据文章Web.xml是什么可知,WEB-INF 和 web.xml 是由J2EE工程规定的,不能随意更改,web.xml是Servlet的配置,如何从头开始写呢?应该使用哪个版本呢?
这个可以去你下载的Servlet服务器容器的 /etc 目录中找到 webdefault.xml
该文件的xml命名空间里说明了该版本容器支持哪个版本的Servlet
例如Jetty8支持的是Servlet2.5 而 Jetty9则是3.0,此时我们得到了两个空的配置文件pom.xml和web.xml
空配置文件
pom.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
web.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
加入工程Target
完成了Web工程配置,此时我们要在pom.xml告诉Maven我们要 编译——汇编——链接 成什么东西,也就是Target叫什么和用什么格式
1 | <project ...> |
SpringMVC+Spring
在完成了Web工程的配置之后,我们开始引入SpringMVC+Spring
修改依赖
在pom.xml文件中加入SpringMVC的依赖,不用添加spring-core因为SpringMVC会自己引用spring-core
1 | <project ...> |
配置SpringMVC作ServletDispatch转发器
修改web.xml 原理参考Servlet原理把SpringMVC作为主入口的转发器, org.springframework.web.servlet 包属于spring-webmvc这个Jar包
1 |
|
此处的 contextConfigLocation 位于 DispatcherServlet的父类FrameworkServlet的第65行 private String contextConfigLocation 所以说spring-mvc.xml是对DispatcherServlet的配置
配置Spring作为Servlet的监听器
在搭建基于SpringMVC的Web服务时,Spring本身并不是必须添加的也就是说applicationContext.xml和listener也不是必须存在,具体原因我们在后边讨论
org.springframework.web.context 包属于spring-web这个Jar包 也就是说我们常说的SSH或SSM中的spring配置其实是指的配置spring-web服务而不是spring-core这个IOC容器
1 | <context-param> |
此处的 contextConfigLocation 位于 ContextLoaderListener的父类ContextLoader的第176行 configLocationParam = sc.getInitParameter(“contextConfigLocation”) 通过同名字符串获取到的configLocationParam 所以说applicationContext.xml是对ContextLoaderListener的配置
配置spring-mvc.xml
如果想让SpringMVC正式提供Web服务,需要以下几个 必要配置 注意在加入mvc命名空间后,需要有对应的xmlns,一般来讲intelliJ IDEA会自动补全
1 | <beans ......> |
配置applicationContext.xml
由于我们没有任何需要Spring控制的Class,所以applicationContext文件内容可以留空
1 | <?xml version="1.0" encoding="UTF-8"?> |
Mybatis
首先明确,Mybatis是JDBC的一个封装,所以说其本身无法离开JDBC,所以说我们要准备一些依赖,其配置可以放在任意一个Context里
依赖的准备
依赖名称 | 作用 |
---|---|
spring-jdbc | Spring的jdbc集成组件 |
mysql-connector-java | MySQL数据库的jdbc组件 |
commons-dbcp | 连接池,用来做数据源dataSource |
mybatis | mybatis核心类,提供mybatis的sqlSessionManage |
mybatis-spring | mybatis与Spring集成的组件 |
1 | <dependency> |
连接池配置
首先我们需要在Spring中启动连接池作为dataSource,而驱动(Driver)就是使用由spring-jdbc和mysql-connector一起提供的 com.mysql.jdbc.Driver 当我们输入数据库和账号密码,一个默认的连接池就启动好了
1 | <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> |
MybatisSpring配置
配置好连接池后,参照MyBatisSpring的配置进行如下配置
配置完毕后就可以使用 DOMapper.java DO.java 和DOMapper.xml进行持久层封装
1 | <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> |
结语
以上是用最少的配置来实现SSM框架,其中很多优化参数都给省去了,具体优化设置请参考其它文章
『重中之重』
applicationContext和spring-mvc配置文件的区别
Spring本身可以提供多个Context,根据StackOverflow的回答回答,当我们需要多个Servlet而不是一个的时候,可以针对不同的Servlet设置不同的配置文件servlet-1.xml、servlet-2.xml,这是在SpringMVC的DispatcherServlet
如果有servlet1和servlet2公用的部分,可以通过配置ContextLoaderListener作为Root Context 以供所有servlet使用,其由Jar包spring-web来实现
Root Context和Servlet Context的区别
由于Root Context是作为公用区域存在的,所以说就导致一个重要的特性 Root Context的Beans可以被不同的Servlet的Bean引用(Reference),但其本身的Bean却不能引用Servlet的Bean
为什么大家都写Root Context
在早先的SSH框架时,准确的说指的是 Struts2 + SpringWeb + Hibernate,由于不能Struts2不能配置ServletContext,所以需要applicationContext配置文件
而使用了 SSM (SpringMVC SpringWeb Mybatis) 之后,为什么不能继续使用applicationContext,还要spring-mvc或者说servletContext这个配置呢?因为SpringMVC的Controller必须配置在servletContext中,加上好多人并不知道 在单一Servlet下Root Context也就是applicationContext是多余的
由此产生的一系列问题
这个问题坑过我好多回,当时不明白为什么现在可以意义解释了
SpringMVC和Spring配置导致事务失效: 因为事务管理器transactionManager是声明在Root Context,而不区分包名导致ServletContext拿到了所有@Service的Bean,为什么是ServletContext拿到,是因为Servlet作为子Context优先级高啊,那么transactionManager就没办法引用@Service导致事务失效
Shiro的注解配置位置不对: 如果想用Shiro的注解对Controller控制,那么必须能对Controller加动态代理,如果按照官方文档放在applicationContext里,自然没办法引用在子Context的@Controller的Class