SSM框架整合流程与原理解读(附源码链接)
本文参考黑马教程,对 MyBatis、Spring、SpringMVC 三个框架进行逐步整合,并对整合后事务失效原因进行总结。
源码链接:https://download.csdn.net/download/weixin_43819566/87690821
文章目录
- 一、搭建整合环境
-
- 1.1 整合项目说明
- 1.2 整合的思路 ★
- 1.3 创建数据库和表结构
- 1.4 创建maven的工程
- 1.5 编写实体类
- 1.6 编写 dao 接口
- 1.7 编写 service 接口和实现类
- 1.9 项目最终目录展示
- 二、Spring 框架代码的编写
-
- 2.1 搭建 Spring 的开发环境
- 2.2 测试 Spring 的开发环境
- 三、SpringMVC 框架代码的编写
-
- 3.1 搭建 SpringMVC 的开发环境
- 3.2 测试 SpringMVC 的开发环境
- 四、Spring 整合 SpringMVC 的框架
-
- 4.1 Spring 整合 SpringMVC 原理解析 ★
- 4.2 Spring 整合 SpringMVC
- 五、MyBatis 框架代码的编写
-
- 5.1 搭建 MyBatis 的开发环境
- 5.2 测试 MyBatis的开发环境
- 六、Spring 整合 MyBatis 框架
-
- 6.1 Spring 整合 MyBatis 原理解析 ★
- 6.2 Spring 整合 MyBatis
- 6.3 mapperLocations 配置的问题
- 七、Spring 框架配置 AOP 与事务控制
- 八、Spring 事务控制失效问题的原因
-
- 8.1 事务不起作用的原因
- 8.2 解决方案
一、搭建整合环境
1.1 整合项目说明
SSM整合会使用多种方式,本文讲述 XML+注解方式
1.2 整合的思路 ★
① 先搭建整合的环境
② 先把 Spring 的配置搭建完成
③ 再使用 Spring 整合 SpringMVC 框架
④ 最后使用 Spring 整合 MyBatis 框架
1.3 创建数据库和表结构
1.4 创建maven的工程
pom.xml 文件引入坐标,并将项目部署到 tomcat 服务器中。pom文件代码如下:
<properties><spring.version>5.2.0.RELEASE</spring.version><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.16</log4j.version><mysql.version>8.0.11</mysql.version><mybatis.version>3.5.6</mybatis.version>
</properties><dependencies><!-- spring aop --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.6.8</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><!--IOC 容器--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><!--spring web--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><!--springmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!--spring测试--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!--spring事务控制--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><!--jdbc模板技术--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!--servlet--><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!--日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!--spring 和 mybatis 整合包--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version></dependency><!--druid数据库连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.3</version></dependency>
</dependencies>
1.5 编写实体类
public class Account implements Serializable {private Integer id;private String name;private Float money;...
}
set、get 方法省略
1.6 编写 dao 接口
public interface AccountDao {/* 查询所有账户*/public List<Account> findAll();/* 根据名称查询账户*/Account findAccountByName(String name);/* 更新账户*/void updateAccount(Account account);
}
1.7 编写 service 接口和实现类
/* 账户业务层接口*/
public interface AccountService {/* 根据id查询账户信息 @return*/List<Account> findAll();/* 转账* @param sourceName 转成账户名称* @param targetName 转入账户名称* @param money 转账金额*/void transfer(String sourceName,String targetName,Float money);
}/* 账户业务层实现类*/
@Service
public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public List<Account> findAll() {System.out.println("业务层查询所有账户");return null;}public void transfer(String sourceName, String targetName, Float money) {System.out.println("转账方法执行");}
}
1.9 项目最终目录展示
二、Spring 框架代码的编写
2.1 搭建 Spring 的开发环境
在项目的 resources 目录下创建 applicationContext.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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--开启注解的扫描--><context:component-scan base-package="com.axy"><!--配置哪些注解不扫描--><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
</beans>
注: Spring 与 SpringMVC 的注解应分开扫描,其容器的 Bean 不会冲突,具体缘由后文会解释。
2.2 测试 Spring 的开发环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestSpring {@Autowiredprivate AccountService as;@Testpublic void testFindAll(){as.findAll();}
}
测试结果:
结果显示:spring 环境初步搭建完成。
三、SpringMVC 框架代码的编写
3.1 搭建 SpringMVC 的开发环境
-
在 web.xml 中配置 DispatcherServlet 前端控制器
<!--配置前端控制器--> <servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--全局初始化参数:让 DispatcherServlet 创建时加载 springmvc.xml--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><!--启动服务器创建该 servlet --><load-on-startup>1</load-on-startup> </servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><!--发任何请求都经过dispatcherServlet--><url-pattern>/</url-pattern> </servlet-mapping>
-
在 web.xml 中配置过滤器解决中文乱码
<!-- 解决中文乱码的过滤器 --> <filter><filter-name>characterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param> </filter><filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern> </filter-mapping>
注:/ 和 /* 的区别和用法
<url-pattern>/</url-pattern> 会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url
<url-pattern>/*</url-pattern> 会匹配所有url:路径型的和后缀型的url(包括/login,.jsp,.js和*.html等)
参考: / 和 /* 的区别和用法 -
创建 springmvc.xml 的配置文件,编写配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--开启注解扫描,只扫描 Controller--><context:component-scan base-package="com.axy.controller" /><!--配置的视图解析器对象--><bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/pages/" /><property name="suffix" value=".jsp" /></bean><!--配置无需过滤的静态资源--><mvc:resources mapping="/static/" location="/static/" /><!--开启 springmvc 注解的支持--><mvc:annotation-driven /> </beans>
3.2 测试 SpringMVC 的开发环境
-
编写 index.jsp 的超链接
<a href="account/findAll">测试查询所有</a>
-
创建 AccountController 类,编写方法进行测试
@Controller @RequestMapping("account") public class AccountController {@RequestMapping("findAll")public String findAllAccount(){System.out.println("表现层查询所有");return "list";} }
测试结果:
测试结果表明:springmvc 搭建完成。
四、Spring 整合 SpringMVC 的框架
目的:在controller中能成功的调用service对象中的方法。
4.1 Spring 整合 SpringMVC 原理解析 ★
javaWeb 中最大的域对象是 ServletContext,随着服务器的启动而创建,随着服务器关闭而销毁。
ContextLoaderListener 监听器,用来监听 ServletContext 域对象的创建和销毁。
当监听到 ServletContext 创建时,去加载 Spring 的配置文件,会创建 WEB 版本的工厂,存储到 ServletContext 对象中。
4.2 Spring 整合 SpringMVC
-
在 web.xml 中配置 ContextLoaderListener 监听器
<!--配置监听器,用于监听ServletContext创建--> <!--默认只加载 WEB-INF 下面的配置文件--> <listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--设置配置文件的路径--> <!--会指示加载类路径下的配置文件--> <context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value> </context-param>
注:
① ContextLoaderListener 监听器实现了 ServletContextListener 接口,用于监听 ServletContext 对象的创建。
② 监听器默认只加载 WEB-INF 下面的配置文件,为了方便管理,最好将 Spring 配置文件放入 resources 文件下。因此可以设置文件的路径,用以指示加载类路径下的配置文件。
③ -
在 controller 中注入 service 对象,调用 service 对象的方法进行测试。
@Controller @RequestMapping("account") public class AccountController {@Autowiredprivate AccountService accountService;@RequestMapping("findAll")public String findAllAccount(){System.out.println("表现层查询所有");accountService.findAll();return "list";} }@Service public class AccountServiceImpl implements AccountService {public List<Account> findAll() {System.out.println("业务层查询所有");return null;}... }
测试结果:
测试结果表明:spring 的配置文件成功被加载。
五、MyBatis 框架代码的编写
5.1 搭建 MyBatis 的开发环境
-
在web项目中创建注配置文件 mybatis.xml,并编写核心配置。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!-- 配置引入外部 properties 文件--><properties resource="druid.properties" /><!--使用 typeAliases 配置别名--><typeAliases><package name="com.axy.domain" /></typeAliases><!--配置环境--><environments default="mysql"><!-- 配置 mysql 的环境--><environment id="mysql"><!-- 配置事务 --><transactionManager type="JDBC" /><!--配置连接池--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></dataSource></environment></environments><!--配置映射标签--><mappers><package name="com.axy.dao"/></mappers> </configuration>
druid.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssmdb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=CST jdbc.username=root jdbc.password=123456 initialSize=5 maxActive=10 maxWait=3000
5.2 测试 MyBatis的开发环境
-
编写账户持久层接口映射文件 AccountDao.xml,映射文件如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.axy.dao.AccountDao"><select id="findAll" resultType="Account">select * from account</select><select id="findAccountByName" resultType="Account">select * from account where name = #{name}</select><update id="updateAccount">update account set money = #{money} where id = #{id}</update> </mapper>
-
映射文件 AccountDao.xml:
public class TestMyBatis {private InputStream in;private SqlSession sqlSession;private AccountDao accountDao;@Beforepublic void init() throws Exception{//1.读取配置文件in = Resources.getResourceAsStream("mybatis.xml");//2.获取SqlSessionFactorySqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//3.获取SqlSession对象sqlSession = factory.openSession();//4.获取dao的代理对象accountDao = sqlSession.getMapper(AccountDao.class);}@Afterpublic void destroy() throws Exception {//提交事务sqlSession.commit();//释放资源sqlSession.close();in.close();}@Testpublic void testFindAll() throws IOException {List<Account> list = accountDao.findAll();for (Account account : list) {System.out.println(account);}} }
测试结果:
结果表明:MyBatis 框架初步搭建完成。
六、Spring 整合 MyBatis 框架
目的:把 mybatis.xml 配置文件中的内容配置到 applicationContext.xml 配置文件中。
6.1 Spring 整合 MyBatis 原理解析 ★
参考:Mybatis从入门到精通系列 02 —— 执行查询的底层原理分析
整体的执行流程,首先需要创建 sqlSessionFactory 工厂,通过工厂创建 sqlSession 对象,在通过 sqlSession 创建代理对象,最后执行查询所有的方法。因此,将 sqlSessionFactory 工厂的创建交给 spring 管理,以后的 sqlSession 对象的全由 IOC 容器中的工厂来创建。有了 sqlSession 可以创建代理对象,最后将代理对象放入 IOC 容器。
6.2 Spring 整合 MyBatis
-
在 spring 的配置文件 applicationContext.xml 中,分别配置连接池、sqlSessionFactory 工厂和 AccountDao 接口所在的包。
<!--spring整合mybatis--> <!--把 sqlSession 的创建交给 IOC 容器--> <!--有工厂可以创建 sqlSession => 有 sqlSession 可以创建代理对象 => 最后将代理对象放入 IOC 容器 --> <!--导入 jdbc 配置文件--> <context:property-placeholder location="classpath:druid.properties" system-properties-mode="FALLBACK" /> <!--配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /> </bean> <!--配置sqlSessionFactory工厂--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 数据源 --><property name="dataSource" ref="dataSource" /><!-- 配置别名 --><property name="typeAliasesPackage" value="com.axy.domain" /><!-- 配置 xml 映射配置文件--><!-- 如果 Mapper.xml 与 Mapper.class 在同一个包下且同名,spring 扫描 Mapper.class 的同时会自动扫描同名的 Mapper.xml 并装配到 Mapper.class。如果 Mapper.xml 与 Mapper.class 不在同一个包下或者不同名,就必须使用配置 mapperLocations 指定 mapper.xml 的位置。--><!--<property name="mapperLocations" value="classpath:mapper/*.xml" />--> </bean> <!--配置AccountDao接口所在的包--> <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.axy.dao" /> </bean>
-
更新账户业务层接口,给 AccountDao 添加依赖注入。
@Service public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;public List<Account> findAll() {System.out.println("业务层查询所有账户");return accountDao.findAll();}public void transfer(String sourceName, String targetName, Float money) {System.out.println("测试转账");//1. 根据名称查询转出账户Account source = accountDao.findAccountByName(sourceName);//2. 根据名称查询转入账户Account target = accountDao.findAccountByName(targetName);//3. 转出账户减钱source.setMoney(source.getMoney()-money);//4. 转入账户加钱target.setMoney(target.getMoney()+money);//5. 更新转出账户accountDao.updateAccount(source);//6. 更新转入账户accountDao.updateAccount(target);} }
-
添加 index.jsp 超链接
<a href="account/update">测试更新账户</a>
-
编写表现层测试方法
@Controller @RequestMapping("account") public class AccountController {@Autowiredprivate AccountService accountService;@RequestMapping("findAll")public String findAllAccount(Model model){System.out.println("表现层查询所有");List<Account> list = accountService.findAll();model.addAttribute("list", list);return "list";}@RequestMapping("update")public String update(){System.out.println("表现层转账!!!");accountService.transfer("aaa", "bbb", 100f);return "success";} }
-
编写成功界面,查看结果。
list.jsp:<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head><title>Title</title> </head> <body><h3>账户信息如下</h3>${requestScope.list}<br>${requestScope.list[0]}<br>${requestScope.list[1]}<br> </body> </html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head><title>Title</title> </head> <body><h3>更新成功</h3><br> </body> </html>
-
测试结果:
测试结果表明:Spring 整合 MyBatis 成功。
另外,mybatis.xml 在整合后除测试外,就不用了。
6.3 mapperLocations 配置的问题
参考:mybatis 整合 spring 之 mapperLocations 配置的问题
Mapper.xml 与 Mapper.class 在同一个包下且同名,spring 扫描 Mapper.class 的同时会自动扫描同名的 Mapper.xml 并装配到 Mapper.class。
如果 Mapper.xml 与 Mapper.class 不在同一个包下或者不同名,就必须使用配置 mapperLocations 指定 mapper.xml 的位置。
例1:如项目中,AccountDao 接口与接口的配置文件有相同的包结构,服务器启动后,class 文件与 xml 文件,会在同一个包下且同名,那么不需要配置<property name=“mapperLocations” value=“classpath:com/axy/dao/*.xml” />
。
例2 :如项目中,AccountDao 接口与接口的配置文件不具有相同的包结构,服务器启动后,class 文件与 xml 文件,会在不同包下,那么需要配置<property name=“mapperLocations” value=“classpath:com/mapper/*.xml” />
。
七、Spring 框架配置 AOP 与事务控制
在 spring 配置文件 applicationContext.xml 中配置事务管理器、事务通知与 AOP
<!--配置 spring 声明式事务管理-->
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" />
</bean><!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*" propagation="REQUIRED" read-only="false" /><tx:method name="find*" propagation="SUPPORTS" read-only="true" /></tx:attributes>
</tx:advice><!--配置AOP增强-->
<aop:config><!--切入点表达式--><aop:pointcut id="pt1" expression="execution(* com.axy.service.impl.*.*(..))" /><!--建立事务通知 与 切入点表达式的对应关系--><aop:advisor advice-ref="txAdvice" pointcut-ref="pt1" />
</aop:config>
参考:Spring 从入门到精通系列 12—— Spring 中的事务控制
测试事务控制:
@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;...public void transfer(String sourceName, String targetName, Float money) {System.out.println("业务层转账");//1 根据名称查询转出账户Account source = accountDao.findAccountByName(sourceName);//2 根据名称查询转入账户Account target = accountDao.findAccountByName(targetName);//3 转出账户减钱source.setMoney(source.getMoney()-money);//4 转入账户加钱target.setMoney(target.getMoney()+money);//5 更新转出账户accountDao.updateAccount(source);// 模拟异常int i = 10/0;//6 更新转入账户accountDao.updateAccount(target);}
}
测试结果(设置账户初试金额为1000):
结果表明,事务已经被控制住了。
自此 SSM 框架完成整合。
八、Spring 事务控制失效问题的原因
参考:ssm整合后配置的事务不起作用的原因和解决方法、SSM框架整合,事务不起作用的原因
假设 springmvc.xml 的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"...><!--开启注解扫描--><context:component-scan base-package="com.axy" />...
</beans>
8.1 事务不起作用的原因
web.xml 文件的加载顺序 context-param -> Listener -> filter -> Servlet(同类级别按照顺序执行)
,即先加载 spring 的配置文件再加载 springmvc 的配置文件,从而先初始化 spring 容器再初始化 springmvc 的容器。
- 由于 SpringMVC 在扫描时扩大了扫描范围,从而导致 Controller 层在注入 Service 时,实际注入的是子容器中的 Service 实例。
- 事务被配置在父容器中,Spring 父容器在装载 Service 时会应用事务配置,而 SpringMVC 只是单纯加载 Service 的实例,没有事务的配置。
- 所以启动服务器,采用就近原则,也就是用了 mvc 容器中的 ServiceImpl 实例,是没有经过事务配置的类。
8.2 解决方案
spring 和 springMVC 的注解扫描一定分开。
springmvc.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"...><!--开启注解扫描--><context:component-scan base-package="com.axy.controller" /><!--方式二:开启注解扫描,只扫描 Controller<context:component-scan base-package="com.axy.controller"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>-->...
</beans>
applicationContext.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"...><!--开启注解的扫描--><context:component-scan base-package="com.axy"><!--配置哪些注解不扫描--><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan></beans>
避坑点:如果设置的包的范围比较大,如:com.axy
事务是不会控制住的。可理解@Controller 注解与 @Service @Component @Repository 拥有一样的效果,@Service 被 springmvc 扫描后,加入 mvc 容器的是没有事务的配置。
<!--开启注解扫描,只扫描 Controller-->
<context:component-scan base-package="com.axy"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>