Spring简介:
Spring是一个IOC(DI)和AOP容器框架:
- 轻量级:Spring是非侵入性的,基于开发的应用中的对象可以不依赖与Spring的API
- 依赖注入(DI - Dependency injection、IOC)
- 面向切面编程(AOP - aspect oriented programming)
- 容器:Spring是一个容器,因为其包含并且管理应用对象的生命周期
- 框架:Spring实现了使用简单的组建配置组合成一个复杂的应用,在Spring中可以使用XML和Java注解组合这些对象
- 一站式:在IOC和AOP的基础上可以整个各种企业应用的开源框架和优秀的第三方类库(Spring自身提供了展现层SpringMVC与持久层Spring JDBC)
Spring模块:
搭建Spring开发环境:
- 导入jar包:
commons-logging.jar(Spring依赖的jar包)
spring-beans.RELEASE.jar
spring-context-RELEASE.jar
spring-core.RELEASE.jar
spring-expression.RELEASE.jar
spring-aop.RELEASE.jar
- Spring的配置文件:一个典型的spring文件项目需要创建一个或多个Bean配置文件,这些配置文件用于在SpringIOC容器里配置Bean.Bean的配置文件可以放在classpath下,也可以放在其他目录下
Spring的设置基本步骤:
- 类路径下创建配置文件:applicationContext.xml(配置bean)
<bean id="customer" class="com.djh.demo.Customer">
<property name="cusName" value="Tom"></property>
</bean>
- 在java Code中加入以下步骤注入bean:
- 创建Spring的IOC的容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- 从IOC容器中获取Bean的实例
Customer customer = ctx.getBean("customer");
Spring Bean的配置
- 配置形式:
- 基于XML文件的方式
- 基于注解的方式
- Bean的配置方式:
- 通过全类名(反射)
- 通过工厂方法(静态工厂方法&实例工厂方法)
- FactoryBean
- IOC容器BeanFactory & ApplicationContext概述
- 依赖注入的方式:
- 属性注入
- 构造器注入
- 注入属性值细节
- 自动专配
- bean之间的关系:
- 继承
- 依赖
- bean的作用域:
- singleton
- prototype
- WEB环境作用域
- 使用外部属性文件
- 在Spring的IOC容器里配置Bean:
- 在xml文件中通过bean节点来配置bean
<bean id="customer" class="com.djh.demo.Customer"> <property name="cusName" value="Tom"></property> </bean>
- id:Bean的名称
- 在IOC容器中必须是唯一的
- 若id没有指定, Spring自动将权限定性类名作为Bean的名字
- id可以指定多个名字,之间用逗号、分号或空格分隔
- Spring提供的两种类型的IOC容器实现:
-
BeanFactory
:IOC容器的基本实现 -
ApplicationContext
:提供了更多的高级特性,为BeanFactory的子接口
-
- ApplicationContext的主要实现类:
- ClassPathXmlApplicationContext:从类路径下加载配置文件
- FileSystemXmlApplicationContext:从文件系统中加载配置文件
- ApplicationContext在初始化上下文时就实例化所有单例的Bean
- 依赖注入的方式(3种):
- 属性注入(即setter方法),属性注入使用<property>元素,使用name属性执行Bean的属性名称,value属性或<value>子节点指定属性值
如:
- 属性注入(即setter方法),属性注入使用<property>元素,使用name属性执行Bean的属性名称,value属性或<value>子节点指定属性值
<bean id="customer" class="com.djh.demo.Customer">
<property name="cusName" value="Tom"></property>
</bean>
- 构造器注入
在<constructor-arg>元素里声明,<constructor-arg>中没有name属性
<bean id="customer" class="com.djh.demo.Customer">
<!-- index参数决定Bean的构造方法中第几个参数,type决定其参数类型 -->
<constructor-arg value="Tom" index="0" type="java.lang.String"></constructor-arg>
</bean>
- 工厂方法注入
对于注入的值包含特殊字符,如:<, >等,需要使用<![CDTAT[xxx]]>来表示 - 引用其他的Bean:
在Bean的配置文件中,可以通过<ref>元素或ref属性为Bean的属性或构造器参数指定对Bean的作用
也可以在属性或构造器里包含Bean的声明,这样的Bean称为内部Bean,不能被外部引用- 注入null值与级联属性:
可以使用<null/>元素标签为Bean的字符串或其他对象类型的属性注入null值
- 注入null值与级联属性:
- SSH均支持级联属性的配置,如:
<property name="customer.cusName" value="Michael" />
对于集合类型的属性,使用list、set或map标签方式,如下:
<property name="customers">
<list>
<ref bean="customer1" /> //或<value>Jacky</value>
<ref bean="customer2" />
</list>
</property>
<map>标签里可以有多个<entry>子标签,每个条目包含一个key与value,简单常量使用key与value来定义,Nean引用通过key-ref与value-ref属性定义
使用<props>定义java.util.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性
Spring自动装配:
- Spring IOC容器可以自动装配Bean,需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式
- byType(根据类型自动装配):Spring IOC 容器中不能有多个与目标Bean类型一致的Bean
- byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同
- Bean的名称与setter方法的名称一致的,如:
- Person Bean:
class Person{
private String personName;
private Address address;
//Getter and Setter method
}
- Address Bean:
class Address{
private String street;
//Getter and Setter method
}
- configure file:
<bean id="address" class="com.djh.demo.Address">
<property name="street" value="TianHe" />
</bean>
<bean id="person" class="com.djh.demo.Person" autowire="byType">
<property name="personName" value="Michael" />
</bean>
constructor(通过构造器自动装配)
- Spring的Bean之间的关系:
- 继承(parent属性),如:
Customer{String:custName, int:age}
<bean id="customer" class="com.djh.demo.Customer"> <property name="age" value="20" /> <property name="custName" value="Lucy" /> </bean> <bean id="customer2" parent="customer"> <property name="custName" value="Michael" /> </bean>
- 依赖(depends-on属性)
Spring允许通过depeds-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好
如果前置依赖于多个Bean,则可以通过逗号、空格的方式配置Bean的名称
- 继承(parent属性),如:
- Spring中Bean的作用域,使用scope属性进行配置,作用域有以下四个,默认为singleton
-
prototype
:容器初始化时不会创建Bean实例,而是在每次请求创建Bean的实例时返回 request
session
-
singleton
:创建IOC容器(ApplicationContext)时就创建了Bean实例,单例的 - 如:
-
<bean id="customer" class="com.djh.demo.Customer" scope="prototype">
<property name="custName" value="djh" />
</bean>
- 使用外部属性文件:
Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,该处理器允许用户将Bean的部分内容移到属性文件中,可以在Bean配置文件中使用形式为${var}
的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量
Spring还允许在属性文件中使用${propName}
,以实现属性之间的相互引用 - 注册PropertyPlaceholderConfigurer
- Spring2.0:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties" />
</bean>
- Spring2.5:
通过<context:property-placeholder>
元素
<beans>中添加context Schema定义,即加入context的Namespaces
在配置文件中加入如下配置:
//导入配置文件
<context:property-placeholder location="classpath:database.properties" />
//导入后可以使用${key}的形式访问配置文件中对应的value
SpEL
- 一个支持运行时查询和操作对象的表达式语言
语法类似于EL,使用#{xxx}
作为定界符,所有在大括号中的字符都被认为是SpEL - SpEL为bean的属性进行动态复制提供了便利
- SpEL可以实现如下功能:
- 通过bean的id对bean进行引用
- 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
- SpEL字面量:
- 整数:
<property name="count" value="#{5}" />
- 小数:
<property name="frequency" value="#{88.2}" />
- 科学计数法:
<property name="capacity" value="#{1e4}" />
- String可以使用单引号或者双引号作为字符串的定界符:
<property name="name" value="#{'djh'}" /> <property name="count" value='#{"Lucy"}' />
- Boolean:
<property name="display" value="#{true}" />
- 整数:
- SpEL引用Bean、属性与方法:
- 引起其他对象(Bean):
<!-- 通过value属性与SpEL配置的ean之间的应用关系 --> <property name="prefix" value="#{prefixGenerator}" />
- 引用其他对象的属性:
<property name="stuffix" value="#{prefixGenerator.stuffix}" />
- 通过其他方法,还可以链式操作:
<!-- 通过value属性和SpEL配置stuffix属性值为另一个Bean的方法的返回值 --> <property name="stuffix" value="#{prefixGenerator.toString()}" /> <!-- 方法的连缀 --> <property name="stuffix" value="#{prefixGenerator.toString().toUpperCase()}" />
- 调用静态方法或静态属性:通过T()调用一个类的静态方法,返回一个类对象
<property name="initValue" value="#{T(java.lang.Math).PI}" />
Spring工厂方法配置Bean
- 调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中
- 要声明通过静态方法创建的Bean,需要在Bean的class属性里指定拥有该工厂方法的类,同时在
factory-method
属性里指定工厂方法的名称,最后使用<constructor-arg>
元素为该方法传递方法参数-
FactoryBean
(接口): -
getObject()
:返回bean对象 -
getObjectType()
:返回bean的类型 -
isSingleton()
:返回bean是否单例
-
注解配置Bean:
- 在classpath中扫描组件
Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件 - 特定组件包括以下几个:
-
@Component
:基本注解,标识了一个受Spring管理的组件 -
@Repository
:标识持久层组件 -
@Service
:标识服务层(业务层)组件 -
@Controller
:标识表现层组件
-
- 对于扫描到的组件,Spring有默认的命名策略,使用非限定类名,第一个字母小写,也可以在注解中通过value属性值标识组件的名称
- 当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明
<context:component-scan>
:
base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类 - 当需要扫描多个包时,可以使用逗号分隔
- 如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类,如:
<context:component-scan
base-package="com.djh.demo.spring.beans"
resource-pattern="autowire/*.class" /> <!-- 表示指定扫描com.djh.demo.spring.beans.autowire下的所有类 -->
- 如下所示:
-
结构:
-
配置文件:
-
各个类的注解:
Person.java:
MockController.java:
DataBaseMockImp.java:
ServiceMock.java:
测试结果:
-
<context:include-filter>
子节点表示要包含的目标类,需要将<context:component-scan>
的use-default-filters
属性的值设置为false. -
<context:exclude-filter>
子节点表示要排除在外的目标类 -
<context:component-scan>
下可以拥有若干个<context:include-filter>
和<context:exclude-filter>
子节点
-
- 使用注解装配Bean与Bean之间的关联关系(组件装配):
<context:component-scan>
元素会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired
和@Resource
、@Inject
注解的属性-
如:
-
测试结果:
-
@AutoWired
自动装具有兼容类型的单个Bean属性:- 构造器,普通字段(即使非public),一切具有参数的方法都可以应用
@Autowired
注解 - 默认情况下,所有使用@Autowired注解的属性都需要被设置,当Spring找不带匹配的Bean装配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Autowired注解的required属性为false.
- 构造器,普通字段(即使非public),一切具有参数的方法都可以应用
-
-
@Resource
注解要求一个Bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为Bean的名称
Spring AOP:
-
AOP
(Aspect-Oriented-Programming)- 解决日志以及代码的混乱问题
- AOP:面向切面编程,是一种新的方法论,是对传统的OOP的补充
- AOP的主要编程对象是切面,而切面模块化切关注点
- AOP的优点:
- 每个事物逻辑位于一个位置,代码不分散,便于维护和升级
- 业务模块更简洁,只包含核心业务代码
- 动态代理的方式处理日志:
-
被代理对象:
-
被代理对象实现类:
-
代理类:
-
测试类:
-
-
AOP分析:
- AOP关键词:
- 切面(
Aspect
):横切关注点被模块化的特殊对象 - 通知(
Advice
):切面必须要完成的工作 - 目标(
Target
):被通知的对象 - 代理(
Proxy
):向目标对象应用通知之后创建的对象 - 连接点(
Joinpoint
):程序执行的某个特定位置,如某个方法调用前、调用后、抛出异常等 - 切点(
pointcut
):每个类都拥有多个连接点。AOP通过切点定位到特定的连接点,一个切点可对应多个连接点
- 切面(
-
AspectJ(Spring2.0以上)为Java社区中最完整最流行的AOP框架,配置方式有以下两种:
- 基于注解
- 基于XML
- 基于注解AspectJ注解支持:
- 必须在classpath下包含AspectJ类库:
aopalliance.jar、aspectj.weaver.jar、spring-aspects.jar
- 将aop Schema添加到
<beans>
根元素中 - 要在Spring IOC容器中启用AspectJ注解支持,只要在Bean配置文件中定义一个空的XML元素
<aop:aspectj-autoproxy>
- 必须要在Bean配置文件中配置需要的Bean,通过
<context:component-scan/>
元素
- 必须在classpath下包含AspectJ类库:
- 当Spring IOC容器侦测到Bean配置文件中的
<aop:aspectj-autoproxy>
元素时,会自动为与AspectJ切面匹配的Bean创建代理 - 使用注解声明一个切面需要两步:
- 把相应的类加到IOC容器中
- 声明该类为一个切面
- 声明执行的位置
- 在配置文件中加入:
<!-- 使AspectJ注解起作用, 自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 如:
-
结构:
-
注解:
-
配置:
-
测试结果:
-
- 在AspectJ注解中,切面只是一个带有
@Aspect
注解的Java类 - 通知就是标注有某种注解的简单的Java方法
- AspectJ支持5种类型的通知注解:
-
@Before
:前置通知,在方法执行之前执行
-
@After
:后置通知,在方法执行之后执行,无论是否发生异常都会执行
-
@AfterRunning
:返回通知,在方法返回结果之后执行
-
@AfterThrowing
:异常通知,在方法抛出异常之后会执行
-
@Around
:环绕通知,围绕着方法执行
-
- 切面优先级的指定:
- 通过加入注解
@Order(number)
, number值越小,优先级越高
- 通过加入注解
- 重用切入点表达式:
-
通过定义一个声明的方法
-
对于非当前类的其他类中的方法,可以使用如下形式:(包名+类名+方法名)
-
- 基于XML配置文件的方式来配置AOP:
-
结构:
-
切面类:
-
配置文件:
-
测试结果:
-
Spring对JDBC的支持:
- 使用JdbcTemplate更新数据库
- 用sql语句和参数更新数据库(update)
public int update(String sql, Object ... args) throw DataAccessException
- 批量更新数据库(batchUpdate)
public int[] batchUpdate(String sql, List<Object[]> batchArgs)
- 查询多行(query)
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Object... args)throws DataAccessException
- 单值查询(queryForObject)
public <T> T queryForObject(String sql, Class<T> requiredType, Object... args) throw DataAccessException
- 用sql语句和参数更新数据库(update)
- 配置文件获取数据库连接信息:
-
结构:
- springContext.xml
<!-- 导入资源文件 --> <context:property-placeholder location ="classpath:db.properties" /> <!-- 配置C3p0数据源 --> <bean id ="dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource"> <property name = "user" value = "${user}"></property> <property name = "password" value = "${password}"></property> <property name = "driverClass" value = "${driverClass}"></property> <property name = "jdbcUrl" value = "${jdbcUrl}"></property> <property name = "maxPoolSize" value = "${maxPoolSize}" ></property> <property name = "initialPoolSize" value = "${initialPoolSize}"></property> </bean>
- db.properties:
user = root password = java driverClass = com.mysql.jdbc.Driver jdbcUrl = jdbc:mysql://localhost:3306/spring maxPoolSize = 10 initialPoolSize = 5
- JdbcTemplate的配置,配置信息如下:
<!-- 配置Spring的JdbcTemplate --> <bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate"> <property name = "dataSource" ref = "dataSource" ></property> </bean>
-
测试结果:
-
- JdbcTemplate的单批更新插入与批量插入:
-
方法:
-
测试结果:
-
- JdbcTemplate的查询:(
queryForObject、queryForList
用于获取某一列的值)-
方法:
-
测试结果:
-
- JdbcTemplate不支持级联属性
- JdbcTemplate是线程安全的,故可以在IOC容器中声明它的单个实例,并将这个实例注入到所有的DAO实例中,如:
-
DAO类:
-
配置DAO依赖注入JdbcTemplate:
-
测试结果:
- spring JDBC框架还提供了一个
JdbcDaoSupport
类来简化DAO实现,该类声明了jdbcTemplate属性,它可以从IOC容器中注入.或者从数据源中创建 - Spring使用
NamedParameterJdbcTemplate
- 经典JDBC中,SQL参数使用占位符(?)表示
- 在Spring JDBC框架中,绑定SQL参数的另一种方式是使用具名参数(named parameter),也即是绑定变量(bind variable)
- 具名参数只在NamedParameterJdbcTemplate中得到支持
- 配置形式:
<!-- 配置具名参数 --> <bean id = "namedParameterJdbcTemplate" class ="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref = "jdbcTemplate"></constructor-arg> <--NamedParameterJdbcTemplate没有无参构造器,必须提供参数--> </bean>
-
如:
-
使用具名参数可以传递对象进行操作,如:
Spring事物管理
- 用于确保数据的完整性与一致性
- 事物的四个关键属性(ACID)
- 原子性(
automicity
) - 一致性(
consistency
) - 隔离性(
isolation
) - 持久性(
durability
)
- 原子性(
- Spring中的事物管理:
- Spring既支持编程式事物管理,也支持声明式事物管理
- 编程式事物管理:将事物管理代码嵌入到业务方法中来控制事物的提交和回滚
- 声明式事物管理:将事物管理代码从业务方法中分离出来,以声明的方式来实现事物管理,可以通过AOP方法模块化,Spring通过Spring AOP框架支持声明式事物管理
- Spring既支持编程式事物管理,也支持声明式事物管理
- Spring的核心事物管理抽象是Interface PlatformTransactionManager,管理封装了一组独立于技术的方法
- Spring中的事物管理器的不同实现:
-
Class DataSourceTransactionManager
:在应用程序中只需要处理一个数据源,且通过JDBC存取 -
Class JtaTransactionManager
:在JavaEE应用服务器上用JTA(Java Transaction API)进行管理 -
Class HibernateTransactionManager
:用Hibernate框架存取数据库
... - 事物管理器以普通的Bean形式声明在Spring IOC容器中
- 声明式事物:
- 配置事物管理器:
<!-- 配置事物管理器 --> <bean id= "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 使用注解事物时,需要启用事物注解 --> <tx:annotation-driven transaction-manager = "dataSourceTransactionManager"/>
- 事物注解,使用
@Transactional
,如:
- Spring事物的传播行为:
- 当事物方法被另一个事物方法调用时,必须指定事物应该如何传播
- 事物的传播行为可以由传播属性指定
- Spring支持的事物传播行为有以下几种:
-
REQUIRED
(默认的传播行为,即使用调用方法的事物) REQUIRED_NEW
SUPPORTS
NOT_SUPPORTED
MANDATORY
NEVER
NESTED
-
- 使用propagation指定传播行为,如:
@Transactional (propagation=Propagation.REQUIRED)
- Spring通过注解设置事物隔离级别、回滚、只读、过期:
- 使用isolation指定事物的隔离级别
- 回滚:默认情况下,Spring的声明式事物对所有的运行时异常进行回滚,可以通过以下属性设置,一般不做设置:
noRollbackFor
rollbackFor
rollbackForClassName
- 只读:该属性通过readOnly设置,取值为true或false,表示这个事物只读取数据但不更新数据,这样可以帮助数据库引擎优化事物
- 过期(超时):使用timeout指定强制回滚之前事物可以占用的时间,单位为秒(S),如ATM机的取款倒计时
-
如:
-
- 回滚:默认情况下,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-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 注解方式自动配置Bean -->
<!--
<context:component-scan base-package="com.djh.spring.transaction"></context:component-scan>
-->
<!-- 导入资源文件 -->
<context:property-placeholder location = "classpath:db.properties"/>
<!-- 配置C3p0数据源 -->
<bean id = "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource">
<property name = "user" value = "${user}" ></property>
<property name = "password" value = "${password}"></property>
<property name = "driverClass" value = "${driverClass}"></property>
<property name = "jdbcUrl" value = "${jdbcUrl}" ></property>
<property name = "maxPoolSize" value = "${maxPoolSize}"></property>
<property name = "initialPoolSize" value = "${initialPoolSize}"></property>
</bean>
<!-- 配置Spring的JdbcTemplate -->
<bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name = "dataSource" ref = "dataSource" ></property>
</bean>
<!-- 配置具名参数 -->
<bean id = "namedParameterJdbcTemplate" class = "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref = "jdbcTemplate" ></constructor-arg>
</bean>
<!-- 配置事物管理器 -->
<bean id = "dataSourceTransactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "dataSource"></property>
</bean>
<!-- 配置Bean -->
<bean id = "bookShopDAO" class = "com.djh.spring.transaction.BookShopDaoImp">
<property name = "jdbcTemplate" ref = "jdbcTemplate"></property>
</bean>
<bean id = "bookShopService" class = "com.djh.spring.transaction.BookShopServiceImp">
<property name = "bookShopDao" ref = "bookShopDAO" ></property>
</bean>
<!-- 配置事物属性 -->
<tx:advice id = "txAdvice" transaction-manager = "dataSourceTransactionManager">
<tx:attributes>
<!-- 根据方法名配置 -->
<tx:method name = "service" propagation = "REQUIRES_NEW" />
<tx:method name = "*" />
</tx:attributes>
</tx:advice>
<!-- 配置事物切入点,将事物切入点与事物属性关联 -->
<aop:config>
<aop:pointcut expression = "execution(* com.djh.spring.transaction.BookShopDao.*(..))" id = "txPointCut" />
<aop:advisor advice-ref = "txAdvice" pointcut-ref = "txPointCut"/>
</aop:config>
<!-- 注解的方式,启用事物注解 -->
<!--
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
-->
</beans>