项目目录结构如下图:
一: 配置文件的约束
约束,就是用到了什么就加上就好,一般以下约束就足够了:
<?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:tx="http://www.springframework.org/schema/tx"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
二:引入外部properties文件,用于配置数据源的参数
jdbc.properties文件如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456
方式一:通过
PropertyPlaceholderConfigurer
类
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:jdbc.properties"/>
</bean>
方式二:通过
context:property-placeholder
标签
<context:property-placeholder location="classpath:jdbc.properties"/>
配置的作用
- 像数据库配置这种随环境变化的文件我们并不想打到war中,而是希望引入war包外的文件。
- 这样配置之后,我们可以在properties文件里随时修改数据源的设置项,
- 同时降低了耦合度.
推荐使用方式二
- 其中属性
location
还提供了file:、http:和ftp:三种前缀,分别通过文件路径、HTTP资源和FTP资源引入文件. - classpath表示类路径,也就是resources目录下.
三: 包扫描, 扫描类注解,把类的对象添加到容器中
<!--注解的包扫描-->
<context:component-scan base-package="com.zuoyueer"/>
配置的作用:
- 扫描base-package指定的包下(包含后代包) 的 @Component、@Service、@Controller、@Repository注解的类,并把这些类注册进Spring容器中管理。
- 如果不加这个配置,那么@Component、@Service、@Controller、@Repository注解将无效,Spring容器中不会有这些注解修饰的类对象
- 实际上@Service、@Controller、@Repository注解是@Component的子注解,目的是区分项目层次,目前版本(5.x)实际作用一样,是Spring保留的一个功能,待以后扩展增强这些子注解
属性
use-default-filters默认值是true,表示所有注解都扫描,因为默认是true所以下面两种写法都一样
<--扫包下全部注解--/>
<context:component-scan base-package="com.zuoyueer"/>
<--扫描包下全部注解--/>
<context:component-scan base-package="com.zuoyueer" use-default-filters="true" />
下面的配置表示,扫描com.zuoyueer包下的部分注解,也就是不包括@Controller修饰的类,
被@Controller修饰的类,不会注册到Spring容器中.
<!-- 实际开发中 spring 配置文件,一般这样配置-->
<context:component-scan base-package="com.zuoyueer" use-default-filters="true">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
下面的配置表示,扫描com.zuoyueer包下的@annotation注解,其他注解不扫描.
<!-- 实际开发中 spring mvc ,一般这样配置-->
<context:component-scan base-package="com.zuoyueer" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
小结:
- use-default-filters 属性的默认值为 true,为true的时候可以省略不写
- true的时候表示 使用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Component, @Service,@Controller和@Repository 的注解的类进行扫描
- false的时候表示 不使用Filter 进行包扫描. 为false的时候不能省略
- 我们希望 SpringMVC 只来控制网站的跳转逻辑,所以我们只希望 SpringMVC 的配置扫描 @Controllerce 注解标注的类,不希望它扫描其余注解标注的类,所以设置了 use-default-filters 为 false,并使用 context:include-filter 子标签设置其只扫描带有 @Controller 注解标注的类。
- 而 Spring 就不同了,我们希望 Spring 仅仅不扫描带有 @Controller 注解标注的类,而扫描其他注解标注的类,而这时建立在使用默认的 Filter 进行扫描的基础上,所以 use-default-filters 为 true
为啥Spring和Spring MVC包扫描要分开?
实际上是一种解耦,使程序易于扩展和维护
大家可以看另外一篇博客有详细解释 https://www.cnblogs.com/moxiaotao/p/9246668.html
三: 配置数据源(连接池)
常用的连接池有C3P0, Druid,HikariCP . 推荐使用HikariCP,它是目前最优秀的连接池,而是SpringBoot2.0的默认连接池就是它.
<!--注册数据源-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
value的值就使用到了jdbc,properties文件中的数据,使用规则就是OGNL(对象导航语言),和El表达意义,是因为EL表达式是它的一部分,
四:配置事务管理器
在Spring中数据库事务是通过PlatformTransactionManager进行管理的,jdbcTemplate是不能支持事务的,而能够支持事务的是org.springframework.transaction.support.TransactionTemplate模板,它是Spring所提供的事务管理器的模板
- 事务的创建、提交和回滚是通过PlatformTransactionManager接口来完成的。
- 当事务产生异常时会回滚事务,在默认的实现中所有的异常都会回滚。我们可以通过配置去修改在某些异常发生时回滚或者不回滚事务。
- 当无异常时,会提交事务。
- 支持JTA事务,常用的是DataSourceTransactionManager,它继承抽象事务管理器AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又实现了PlatformTransactionManager。这样Spring就可以如同源码中看到的那样使用PlatformTransactionManager接口的方法,创建、提交或者回滚事务了。
用得最多的事务管理器是DataSourceTransactionManager(org.springframework.jdbc.datasource.DataSourceTransactionManager),因此下面将以此例进行讲解。如果使用的持久框架是Hibernate,那么你就要用到spring-orm包org.springframework.orm.hibernate4.HibernateTransactionManager了。它们大同小异.
下面配置一个事务管理器
<!--配置事务管理器,注意这个id,下面一节会用到-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
使用DataSourceTransactionManager去定义数据库事务管理器,并且注入了数据库连接池。这样Spring就知道你已经将数据库事务委托给事务管理器transactionManager管理了。在jdbcTemplate源码分析时,数据库资源的产生和释放如果没有委托给数据库管理器,那么就由jdbcTemplate管理,但是此时已经委托给了事务管理器,所以jdbcTemplate的数据库资源和事务已经由事务管理器处理了。
五: 配置事务驱动
- 首先必须说的的:Srping声明式事务管理有2种,一种是XML方式,一种是注解方式,
- 如果使用XML方式,该配置不用配置
- 如果使用了注解的方式,该配置必须写,如果不配置,那么注解(声明事务)将无效
下面是配置事务驱动
<tx:annotation-driven transaction-manager="transactionManager"/>
事务驱动的作用: 解析项目中的@Transactionl 注解
- 属性
transaction-manager
的作用是指定事务驱动的事务管理器,transactionManager
是第四节中配置的事务管理器的id
属性值. - Spring默认的事务管理器的id是
transactionManager
, - 如果我们自己配置的事务管理器的
id
值不是transactionManager
而且配置事务驱动的时候不指定事务管理器,那么Spring就会去找默认的,结果找不到,就会报错. - 如果我们自己配置的事务管理器的
id
值是transactionManager
,因为默认的事务管理器的id是transactionManager
,所以在配置事务驱动的时候可以不指定事务管理器. - 总之,为了不错出,建议配置事务驱动的时候指定事务管理器,也就是
transaction-manager
属性得加上
六: 配置AOP驱动
首先必须说的是: 和事务驱动一样,如果是通过XML方式实现AOP操作,那么可以不配置该驱动,如果是注解方式实现AOP操作,那么必须配置AOP驱动.
第一种配置
<!--开启AOP注解驱动-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
或者
<aop:aspectj-autoproxy />
配置AOP驱动作用: 解析AOP相关的注解
- 属性
proxy-target-class
的默认值是false,如果是false可以省略不写 - false表示使用
JDK动态代理
织入通知到切入点. - true表使用
CGLIB动态代理
织入通知到切入点, - 实际上,即使设置成false,如果切入点所在类没有实现相对应接口,那么Spring也会自动使用CGLIB动态代理
- 总之,我们不用
proxy-target-class
属性就好了.一切交给Spring自己处理吧
七: 注册SqlSessionFactory
- 在基本的MyBatis中,SqlSessionFactory可以使用SqlSessionFactoryBuilder来创建
- 而我们使用了
MyBatis-Spring
类库整合了MyBatis,MyBatis-Spring
帮助我们将MyBatis代码无缝的整合到了Spring中. 这个类库提供了简单的方式来注入MyBatis数据映射器和SQLSession到Spring容器中. - SqlSessionFactoryBean实现了Spring的FactoryBean接口。这意味着Spring最终返回的不是SqlSessionFactoryBean而是作为factory 的getObject()方法返回的结果,即SqlSessionFactory对象 .这相当于下面的java代码:
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sessionFactory = factoryBean.getObject();
- SqlSessionFactory有一个必须的属性:dataSource, 也就是必须配置数据源
注册SqlSessionFactory:
<!--注册SqlSessionFactory, 因为SqlSessionFactory是接口,所以使用SqlSessionFactoryBean来注册-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--引入数据源(必须)-->
<property name="dataSource" ref="dataSource"/>
<!--引入别名-->
<property name="typeAliasesPackage" value="com.zuoyueer.domain"/>
<!--引入mybatis的配置文件(全局配置文件)-->
<property name="configLocation" value="SqlMapConfig.xml"/>
</bean>
因为Spring整合Mybatis,所原来在myBatis配置文件中的设置都能在spring配置文件中做.
重要的事情多说一遍,注册SqlSessionFactory必须引入数据源!
八: 加载映射文件
在很久以前,使用MapperFactoryBean创建的代理类实现了 Mapper 接口,并且注入到Spring容器中,但是这种做法已经淘汰了,因为系统有很多的配置文件时 全部需要手动编写,而且没有必要在 Spring 的 XML 配置文件中注册所有的映射器.
于是MapperScannerConfigurer
就应运而生了.MapperScannerConfigurer
它将会查找类路径下的映射器并自动将它们创建成MapperFactoryBean。
加载映射文件
<!--加载映射文件, 配置 Mapper 扫描器 注册Mapper的包扫描 代替了Mybatis中Mappers标签-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zuoyueer.dao"/>
<!--指定SqlSessionFactory,实际上是指定数据源,在单数据源的项目中,这给可以不写-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
basePackage
属性是让你为映射器接口文件设置基本的包路径。 你可以使用分号或逗号 作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到。
- 为什么sqlSessionFactoryBeanName要用value而不用ref?
在mybatis-spring1.1.0以前,是通过将SqlSessionFactory对象注入到sqlSessionFactory,这样做可能会有一个问题,就是在初始化MyBatis时,jdbc.properties文件还没被加载进来,dataSource的属性值没有被替换,就开始构造sqlSessionFactory类,属性值就会加载失败。在1.1.0以后,MapperScannerConfigure提供了String类型的sqlSessionFactoryBeanName,这样将bean name注入到sqlSessionFactoryBeanName,这样就会等到spring初始化完成后,再构建sqlSessionFactory。 - 如果在多数据源的项目中,这里必须指定SqlSessionFactory,实际上是指定数据源
- 如果Mapper.xml与Mapper.class不在同一个包下或者包不同名,
这种情况下就不能使用包扫描了,而应该在注册SqlSessionFactory中配置mapperLocations,来指定映射文件
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--引入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--引入别名-->
<property name="typeAliasesPackage" value="com.zuoyueer.domain"/>
<!--引入mybatis的配置文件-->
<property name="configLocation" value="SqlMapConfig.xml"/>
<!--接口的包名和配置文件的包名不一样的时候使用mapperLocations来指定映射配置文件-->
<property name="mapperLocations" value="classpath*:com/zuoyueer/dao/*.xml"/>
</bean>
classpath:
表示在类路径下找,也就是sources下
classpath*:
表示在全部路径下找也就是src和sources下
其中*
是个通配符,代表任意的字符串或者某个文件
**
代表任意多级目录:比如 classpath:com/**/User*.xml
表示在sources目录找,com目录下(包括后代目录)的全部以前缀名是User的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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--引入外部配置-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--注解的包扫描-->
<context:component-scan base-package="com.zuoyueer" use-default-filters="true"/>
<!--开启事务驱动,必须指定事务管理器,默认的事务管理器名称是transactionManager,
如果事务管理器的名称不是transactionManager,而且这里没指定,那么会报错-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--开启AOP注解驱动-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
<!--注册SqlSessionFactory, 因为SqlSessionFactory是接口,所以使用SqlSessionFactoryBean来注册-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--引入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--引入别名-->
<property name="typeAliasesPackage" value="com.zuoyueer.domain"/>
<!--引入mybatis的配置文件-->
<property name="configLocation" value="SqlMapConfig.xml"/>
<!--映射文件和接口的包名不一样的时候才配置这个-->
<property name="mapperLocations" value="classpath*:com/zuoyueer/dao/*.xml"/>
</bean>
<!--加载映射文件, 配置 Mapper 扫描器 注册Mapper的包扫描 代替了Mappers标签-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zuoyueer.dao"/>
<!--指定注册SqlSessionFactory,实际上是指定数据源,在单数据源的项目中,这给可以不写-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!--创建数据源-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Mybatis的配置文件: SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 里的配置,是需要按照顺序来的,顺序是:properties,settings,typeAliases,environments,mappers,-->
<configuration>
<!--该文件实际上可以删除,因为已经整合到了spring.xml中了,但是以后还有用,就留着-->
</configuration>
映射文件: AccountDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace是命名空间,必须唯一,他是指是接口的全限定名 -->
<mapper namespace="com.zuoyueer.dao.AccountDao">
<select id="findByName" parameterType="string" resultType="account">
select * from account where name = #{name}
</select>
<update id="edit" parameterType="account">
update account set name=#{name} ,money=#{money} where id=#{id}
</update>
</mapper>
Maven依赖
<dependencies>
<!-- mybatis整合spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--Spring核心容器-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--SpringJdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--事务相关的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--SpringAOP相关的坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<!--Spring整合单元测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--HikariCP连接池-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.1.0</version>
</dependency>
<!--myBatis坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--日志的坐标-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
其他的就不放上来了,因为每个项目都不一样,本文主要讲解的就是Spring.xml怎么写,以及相关配置的作用和注意.
如果本文有错,请指正.谢谢!
参考文献(这些博客也不一定是原创,在此谢谢(原创)大牛的分享):
https://my.oschina.net/u/1020238/blog/509159/
https://www.jianshu.com/p/adf2486ba56e
https://www.cnblogs.com/zhuzihan/p/9100617.html
https://www.cnblogs.com/sanxiao/p/9599308.html