Spring框架2
一. Spring AOP的概念以及介绍
1. 概念:
-
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
-
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。
2. Aop功能:
- Aop的功能主要是为了拦截或者实现日志安全检查,一些检查的工作,aop也常用于事务管理,防止垃圾数据进入数据库。
3. 横向切割和纵向切割:
- Aop采用的横向切割技术,在不修改源代码的情况下完成添加功能的技术;
- 纵向切割技术,修改源代码情况下完成功能的操作
4.Aop里有五种增强的方式:
-
增强/通知其实一个要添加的逻辑业务处理的方法,五种实现横向切割技术的方式
-
前置增强,表示在目标方法执行前实施增强
-
后置增强,表示在目标方法执行后实施增强
-
引介增强,表示在目标类中添加一些新的方法和属性。(了解)
-
环绕增强,表示在目标方法执行前后实施增强
-
异常增强,表示在目标方法抛出异常后实施增强。
-
最终增强,表示在目标方法执行后不管有没有异常抛出总是实施增强
-
二. Spring AOP的应用
1. 准备工作
- 加入依赖坐标
- Aspectij这个jar包,不是spring框架的一部分,可以作为spring框架的一个组件,用来配合aop完成相应的操作
<dependencies>
<!-- junit的jar包坐标 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
-
创建核心配置文件并且加入相应的约束
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>
2. 基于aspectJ的xml版
1. 创建一个目标类
/* 目标类,就是在操作过程中手动调用的类
*/
public class TargetClass {
public void login(){
System.out.println("目标类方法:登录成功");
}
}
2. 创建一个增强类
/*
* 增强类,在调用目标类的时候spring利用aop思想,执行预编译的类
*/
public class HandleClass {
public void check(){
System.out.println("登录校验检查");
}
}
3. 修改核心配置文件,加入bean管理和aop配置
- 前置增强
<!-- 对目标类进行bean注册 -->
<bean id="targetClass" class="cn.kgc.xml.TargetClass"></bean>
<!-- 对增强类进行bean注册 -->
<bean id="handleClass" class="cn.kgc.xml.HandleClass"></bean>
<!-- aop编程思想 -->
<aop:config>
<!-- 切点 对应的是目标类的方法,在aop配置中可以有多个aop:ponitcut
expression称之为表达式,属性值等于execution(* cn.kgc.xml.TargetClass.login(..))
execution表示执行,该方法中三个参数,参数1表示* ,参数2是一个空格,参数3表示目标类方法的地址
参数3方法中一定要携带两个点作为参数,第一个点表示参数类型,第二点表示参数名称,
注意:不管你的方法中是否有参数,都必须有两个点
id属性表示切点名称
-->
<aop:pointcut expression="execution(* com.kgc.xml.TargetClass.login(..))" id="mycut1"/>
<!-- 切面 对应的是增强类的方法 ref映射增强类的bean注册id -->
<aop:aspect ref="handleClass">
<!-- 前置增强
method属性表示方法的意思,对应的是增强类的中具体的方法名称
pointcut-ref表示当前切面中的方法所对应的切点
-->
<aop:before method="check" pointcut-ref="mycut1"/>
</aop:aspect>
</aop:config>
public void handleBefore(){
System.out.println("前置增强方法--取款操作前的用户校验");
}
- 后置增强
<aop:after-returning method="handleAfter" pointcut-ref="myPointCut"/>
public void handleAfter(){
System.out.println("后置增强方法--取款后的信息输出");
}
- 环绕增强
<aop:around method="around" pointcut-ref="myPointCut"/>
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("检查前。。。");
pjp.proceed();//调用切点方法
System.out.println("检查后。。。");
}
- 异常增强
- 在业务目标方法中出现类异常情况,则会执行异常增强,如果不存在异常,则不执行异常增强
<aop:after-throwing method="excep" pointcut-ref="myPointCut"/>
public void excep(){
System.out.println("出错啦");
}
-
最终增强
不管有没有异常出现,均会执行的增强称之为最终增强
<aop:after method="finallyHandle" pointcut-ref="myPointCut"/>
public void finallyHandle(){
System.out.println("最终增强--关闭资源");
}
4. 测试类
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
TargetClass target = (TargetClass) context.getBean("target");
target.getMoney();
}
3. 基于注解版
1. 修改核心配置文件,加入注解驱动
<!-- 开启spring注解驱动 -->
<context:component-scan base-package="com.kgc.anno"></context:component-scan>
<!-- 开启aop切面注解驱动(aop执行自动动态代理)-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2.注意事项:
- 目标类要设置@service注解,目的是为了在调用service时候完成实例化和注入操作
- 增强类要设置@Aspect切面注解,目的是定义当前类是切面,而且也要设置@service注解,目的也是为了在完成实例化和注入操作
- 注意:注解开发,主要更改的是增强类里的注解配置
3.增强类
@Service // 实例化 增强类
@Aspect // @Aspect 表示 增强类 为切面
public class HandleClass {
//前置增强
@Before("execution(* com.kgc.anno.TargetClass.getMoney(..))")
public void handleBefore(){
System.out.println("注解版前置增强方法--取款操作前的用户校验");
}
//后置增强
@AfterReturning("execution(* com.kgc.anno.TargetClass.getMoney(..))")
public void handleAfter(){
System.out.println("注解版后置增强方法--取款后的信息输出");
}
//环绕增强
@Around("execution(* com.kgc.anno.TargetClass.getMoney(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("注解版检查前。。。");
pjp.proceed();//调用切点方法
System.out.println("注解版检查后。。。");
}
//异常增强
@AfterThrowing("execution(* com.kgc.anno.TargetClass.getMoney(..))")
public void excep(){
System.out.println("注解版出错啦");
}
//最终增强
@After("execution(* com.kgc.anno.TargetClass.getMoney(..))")
public void finallyHandle(){
System.out.println("注解版最终增强--关闭资源");
}
}
4.目标类
@Service//实例化 目标类
public class TargetClass {
public void getMoney(){
System.out.println("目标方法:取款!");
// int i=1/0;
}
}
5.测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/applicationContext.xml")
public class TestAop {
@Autowired
TargetClass target;
@Test
public void test1(){
target.getMoney();
}
}
4. Spring的事务管理
1. 事务的概念:
事务管理对于企业应用而言至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失。
简单来说:事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了确保数据的完整性和一致性,在目前企业级应用开发中,事务管理是必不可少的
2. 事务的属性:
-
传播行为
-
隔离级别
-
只读提示
-
事务超时间隔
-
回滚原则
-
事务的属性:是对事务策略如何应用到方法上的描述。
-
传播行为
定义了事务应用到方法上的边界。也就是什么时候开始一个新的事务,或者什么时候事务被暂停,或者方法是否要在事务中运行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1kBakXE-1571645408029)(C:\Users\CX\AppData\Roaming\Typora\typora-user-images\1556431163971.png)]
-
隔离级别
用来指定一个事务受其他并发事务活动影响的程度。隔离性是数据的事务的4个特征之一,但是实际上来说,用户使用数据库产品是需要在效率和安全上找到平衡点的,所以需要设置事务的隔离级别;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IdS9yRoR-1571645408030)(C:\Users\CX\AppData\Roaming\Typora\typora-user-images\1556431188395.png)]
-
只读提示
Read-only=true,必须配合传播行为来设置。一般建议设置在查询的方法中,
-
事务超时间隔
可以让事务在特定的秒数后自动回滚,不必等到它自己结束。它也必须配合传播行为来设置。Timeout=5
-
回滚规则
默认情况下在出现运行时异常RuntimeException才会回滚。检查时异常不回滚。当然也可以改变这种规则。
5. 声明式事务(常用)
-
声明式事务管理:它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。
-
声明式事务管理有三种方法实现,分别是TransactionProxyFactoryBean的代理方式、基于AspectJ的xml配置方式和基于注解的声明方式,后两种在开发应用中常常出现。
-
声明式事务管理是基于AOP思想完成的,类似与在给业务层加入切面,对事务操作前后进行一定的事务管理控制。
1.基于注解版–转账案例
- 修改核心配置文件
<!--开启 类的注解 切点的注解-->
<context:component-scan base-package="com.kgc"></context:component-scan>
<!--开启切点的注解-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--实例化 jdbc模板对象 需要数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--创建一个自己的dataSource-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/k8514?characterEncoding=utf-8"/>
<property name="user" value="root"/>
<property name="password" value="ROOT"/>
</bean>
<!--配置事务 管理 需要数据源 数据源有回滚 rollback(撤回)方法 -->
<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启 事务的注解 -->
<tx:annotation-driven transaction-manager="transactionManager1"></tx:annotation-driven>
- Dao实现类
@Repository
public class AccountDaoImpl implements AccountDao{
@Autowired
private JdbcTemplate template;
@Override
public void outAccount(String outCard, double money) {
String sql="update account set money=money-? where account=?";
template.update(sql, money,outCard);
}
@Override
public void inAccount(String inCard, double money) {
String sql="update account set money=money+? where account=?";
template.update(sql, money,inCard);
}
}
- Service实现类
@Transactional//事务的注解,表示当前类下的所有方法均加入事务
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao dao;
@Override
public void transferAccounts(String inCard, String outCard, double money) {
dao.outAccount(outCard,money);
//int i=1/0;
dao.inAccount(inCard,money);
}
}
- 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/applicationContext.xml")
public class TestTx {
@Autowired
private AccountService service;
@Test
public void testTx1(){
service.transferAccounts("曹操","刘备",50);
System.out.println(1);
}
}