Spring框架(二)
整合Junit4单元测试
传统测试代码,测试spring时每个测试方法中都需要创建spring容器,测试非常麻烦,整合了Junit测试之后,可以在测试类中自动帮我们创建spring容器.我们可以不用每次测试都创建容器了.提高书写代码的效率.
导包
- spring-beans spring-context spring-core spring-expression com.springsource.org.apache.log4j com.springsource.org.apache.commons.logging
- spring-aop
- spring-test junit4
搭建spring框架
准备对象
创建Spring配置
新建applicationContext.xml,导入约束
整合junit4测试
//在测试方法运行前先自动创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定配置文件路径
@Contextcontfinguration("classpath:applicationContext.xml")
public class Demo{
//将待测对象注入us属性中,name属性填写BeanName
@Resource(name="userService")
private UserService us;
Spring中的AOP开发
AOP思想
AOP思想:面向切面编程
纵向重复,横向抽取.
spring中aop开发概念
spring封装了代理技术,通过代理技术来体现aop思想,我们使用代理体现aop时,不需要我们自己书写代理代码,spring帮我们完成.
spring中封装的代理技术
动态代理
局限性:生成代理类时,必须基于接口,生成的代理对象实际上就是接口的实现类.spring中的aop是希望能够对象所有对象生成代理的.基于该动态代理原则,会导致项目中很多类无法生成代理.
CGLib代理
spring为了能够对项目中所有类生成代理,所以引入了CGLib代理技术,该代理技术的特点是,对目标对象生成代理时,代理对象是被代理对象的子类.Hibernate应用了CGLib代理,懒加载技术中返回的就是cglib代理对象.
aop中的名称解释
aop联盟制定规范
- 连接点 join point:目标对象中所有可以增强的方法.
- 切点 point cut:已经或即将增加的方法.
- 通知 advice:我们需要对目标方法增强的代码.
- 目标对象 target:我们需要增强的对象
- 代理对象 proxy:将通知应用到目标对象生成的对象
- 织入 weaving:将通知织入到目标对象的过程.
- 切面 aspect|advistor:切点+通知
springAOP开发步骤(xml)
导包
- spring-beans spring-context spring-core spring-expression com.springsource.org.apache.log4j com.springsource.org.apache.commons.logging
- spring-aop spring-aspect
- aspect织入包 aop联盟规范包
- spring-test junit4
准备目标对象
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("添加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void find() {
System.out.println("查找用户");
}
}
准备通知对象
使用方法表达通知
- 前置通知
- 环绕通知
- 后置通知-如果目标方法抛出异常,就不执行通知
- 后置通知-无论目标方法是否抛出异常,都执行通知
异常拦截通知
@Before(“MyAdvice.myPC()”)
public void before(){
System.out.println(“我是前置通知”);
}public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println(“我是环绕通知前半部分”);
Object proceed = pjp.proceed();
System.out.println(“我是环绕通知后半部分”);
return proceed;
}public void afterReturning(){
System.out.println(“我是后置通知-如果目标方法抛出异常,就不执行通知”);
}public void after(){
System.out.println(“我是后置通知-无论目标方法是否抛出异常,都会执行通知”);
}public void afterThrowing(){
System.out.println(“我是异常拦截通知”);
}
配置生成代理对象
applicationContext.xml配置
- 注册目标对象
- 注册通知对象
配置切面(切点+通知)
切点表达式语法 public void cn.itcast.service.UserServiceImpl.save() void cn.itcast.service.UserServiceImpl.save() 修饰符任意 * cn.itcast.service.UserServiceImpl.save() 返回值任意 * cn.itcast.service.*ServiceImpl.save() 任何以ServiceImpl结尾的类 * cn.itcast.service.*ServiceImpl.*() 任何方法 * cn.itcast.service.*ServiceImpl.*(..) 任意参数 =>开发时使用的 * cn.itcast.service..*ServiceImpl.*(..) 包含子孙包 => 开发时使用的 配置切点 id:为切点起个名字 expression:填写切点表达式 配置切面 ref:指定通知对象 前置通知切面 method:通知方法 pointcut-ref:qiedian
springAOP开发步骤(注解)
前面步骤相同
1. 注册目标对象
2. 注册通知对象
3. 开启使用注解配置aop
- @Aspect 表示该类是通知类
- @Before(“execution(表达式)”) 前置通知
- @Around(“execution(表达式)”) 环绕通知
- @AfterRunner(“execution(表达式)”) 后置通知
- @After(“execution(表达式)”) 后置通知,不管是否抛异常,都执行
@AfterThrowing(“execution(表达式)”) 异常拦截通知
//注册切点
@Pointcut(“execution(* cn.itheima.service.impl.ServiceImpl.())”)
public void myPC(){}
Spring中的aop事务
使用spring中的aop技术来管理事务
事务属性
事务隔离级别
- 1 读未提交
- 2 都已提交
- 4 可重复读
- 8 串行化
事务是否只读
true 只读
false 可修改
传播行为
当业务方法平行调用时,事务应如何管理.
PROPAGION_XXX :事务的传播行为
保证同一个事务中
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
springAOP事务管理(xml)
导包
- spring-beans spring-context spring-core spring-expression com.springsource.org.apache.log4j com.springsource.org.apache.commons.logging
- spring-aop spring-aspect
- aspect织入包 aop联盟规范包
- spring-test junit4
- spring-jdbc spring-tx
- 数据库驱动 c3p0连接池
创建Dao层对象
@Override
public void increaseMoney(Integer id, Double money) {
String sql = "update t_user set money=money+? where id=?";
getJdbcTemplate().update(sql,money,id);
}
@Override
public void decreaseMoney(Integer id, Double money) {
String sql = "update t_user set money=money-? where id=?";
getJdbcTemplate().update(sql,money,id);
}
创建service层对象
public class BalanceServiceImpl implements BalanceService {
private BalanceDao bd;
public void transfer(Integer from, Integer to, double money) {
bd.increaseMoney(to, money);
bd.decreaseMoney(from, money);
}
public void setBd(BalanceDao bd){
this.bd = bd;
}
}
创建spring配置文件
连接池
<!-- 指定读取db.properties中的键值对 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
dao层配置
<!-- dao -->
<bean name="balanceDao" class="cn.it.dao.impl.BalanceDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
service层配置
<!-- service -->
<bean name="balanceService" class="cn.it.service.impl.BalanceServiceImpl">
<property name="bd" ref="balanceDao"></property>
</bean>
AOP事务配置
事务核心事务管理器
<!-- 配置核心事务管理器 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
配置事务通知&事务属性
引入tx约束
propagation:传播行为
read-only:是否只读
isolation:隔离级别
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="delete*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="update*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true" isolation="DEFAULT"/>
<tx:method name="*" propagation="REQUIRED" read-only="false" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
配置切面完成织入
<!-- 配置织入 -->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut expression="execution(* cn.itheima.service.impl.*ServiceImpl.*(..))" id="txPC"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPC"/>
</aop:config>
springAOP事务管理(注解)
- 导包
- 创建Dao层对象
- 创建Service层对象
- 创建Spring配置对象
与xml相同
AOP事务配置
事务核心事务管理器
<!-- 配置核心事务管理器 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
开启使用注解配置事务
<tx:annotation-driven transaction-manager="transactionManager" />
使用注解管理事务
//类中的所有方法都应用aop事务
@Transactional(propagation=Propagation.REQUIRED,readOnly=true,isolation=Isolation.REPEATABLE_READ)
public class BalanceServiceImpl implements BalanceService {
private BalanceDao bd;
@Override
@Transactional(propagation=Propagation.REQUIRED,readOnly=false,isolation=Isolation.REPEATABLE_READ)
public void transfer(Integer from, Integer to, double money) {
bd.increaseMoney(to, money);
bd.decreaseMoney(from, money);
}
public void setBd(BalanceDao bd){
this.bd = bd;
}
}