AOP的概念
通过约定编程的例子发现,只要按照以定的规则,我们就可以将你的代码织入事先约定的流程中。Spring AOP就是一种约定编程。
为什么使用AOP
AOP最典型的应用实际就是数据库事务的管控。
举例,当用户A在银行转账给用户B的时候,A的账户扣款和B的账户收款要一并保存到数据库中。流程如下
这里的A扣款和B收款我们都已使用面向对象编程(OOP)进行设计,但是他们在数据库事务中的要求是,要么一起成功,要么一起失败,这样OOP就无能为力了。我们可以使用AOP来解决。
AOP可以减少大量的重复工作。在使用AOP之前我们看看之前是怎么做的
AOP之前的操作(JDBC)
TransferServince
public class TransferService(){
public int transferMoney(User userA,User userB,int money){
TransferDao transferDao = new TransferDao();
Connection conn = null;
int result = 0;
try{
//获取数据库事务连接
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/aop","root","123456");
// 非自动提交事务
conn.setAuoCommit(false);
result = transferDao.delMoney(conn,userA.getId,money);
result = transferDao.addMoney(conn,userB.getId,money);
conn.commit;
}catch(Exception e){
try{
//回滚事务
conn.rollback();
}catch(SQLException ex){
ex.printStackTrace();
}
e.printStackTrace();
}finaly{
//释放数据库连接资源
if(conn!==null){
try{
conn.close();
}catch(SQLException ex){
ex.printStackTrace();
}
}
}
return result;
}
}
TransferDao
public class TransferDao{
public int delMoney(conn,userA.getId,money) throws SQLException{
PreparedStatement ps = null;
try{
ps=conn.prepareStatement("update SQL--------");
return ps.executeUpdate();
}finally{
ps.close();
}
}
public int addlMoney(conn,userA.getId,money) throws SQLException{
PreparedStatement ps = null;
try{
ps=conn.prepareStatement("update SQL--------");
return ps.executeUpdate();
}finally{
ps.close();
}
}
}
我们可以看到获取数据库事务连接,事务操控和关闭数据库连接的过程,都需要使用大量的try
…catch
…finally
…语句去操作,存在很多重复的工作。那么是否可以替换这些没有必要重复的工作呢,答案是肯定的,因为这里存在一个默认的流程约定,我们先描述一下这个流程。
(1)获取并打开数据库连接,然后参数进行设置;
(2)执行sql语句
(3)如果没有异常,则提交事务
(4)如果发生异常,则回滚事务
(5)关闭数据库事务连接
具体流程图如下:
这张图和我们之前按的约定编程有一点类似,看下图
这样是不是清晰了,关于数据库的打开和关闭及事务的提交和回滚都有流程默认给你实现。换句话说,你都不需要完成它们。你需要完成的任务是编写SQL这一步而已,然后织入流程中。在基于spring 开发的代码中,我们会经常看到这样的代码:
@Autowired
private userDao;
@Transacational
public int insertUser(User user){
return userDao(user);
}
当然@Transacation
这只是AOP的一种约定编程,被它注解的代码说明需要事务运行,Spirng帮你把insertUser方法织入类似上图的流程中,数据库连接的打开和关闭以及事务管理都由它给你默认实现,也就是它可以将大量重复的流程通过约定的方式抽离出来,然后给与默认实现。例如这里的数据库打开释放,事务的处理和大量的try…catch…finally语句代码块。
这里没有任何数据库打开和关闭的代码,也没有事务回滚和提交的代码,却实现了数据库资源的打开和关闭以及事务的回滚和提交。
AOP的优点
Spring AOP可以处理一些无法使用OOP实现的业务逻辑。其次,通过约定可以将一些业务逻辑织入流程中,并且可以将一些通用的逻辑抽离出来,然后给与默认实现,这样你只需要完成部分的功能就可以了。这样做可以使得开发者的代码更加简短,同时可维护性也得到提高。
AOP的术语
- 连接点(join point ):对应的是具体被拦截的对象,因为spring只能支持方法,所以被拦截的对象往往就是指特定的方法。例如用户的插入insertUser()方法就是一个连接点,AOP通过动态代理技术把它织入到对应的流程中。
- 切点(point cut):有时候,我们的切面不单单应用于单个方法,也可能是多个类的不同方法,这时,可以通过正则式和指示器规则去定义,从而适配连接点。切点就是提供这样一个功能的概念。
- 通知(advice): 就是按照约定的流程下的方法,分为前置通知(before advice),后置通知(after advice),环绕通知(around advice),事后返回通知(afterReturning advice),异常通知(afterThrowing advice),它会根据约定织入流程中,需要弄明白它们在流程中的顺序和运行的条件。
- 目标对象(target):即被代理对象,例如我们写的ServiceImpl服务层实现类的实例
- 引入(introduction):是指引入新的类和其方法,增强现有Bean的功能。
- 织入(weaving):它是一个通过动态代理技术,为原有服务对象生成代理对象,然后将与切点定义匹配的连接点拦截,并按照约定将各类通知织入约定流程的过程。
- 切面(aspect):是一个可以定义切点,各类通知和引入的内容,spring aop通过它的信息来增强Bean的功能或者将对应的方法织入流程。