前言
在以前的项目中,很少去关注Spring AOP的实现原理,只是简单了解了一下什么是AOP具体怎么用,本篇将不介绍其使用方法,主要其实如何实现的(即实现原理是什么)。
AOP 指的是面向切面编程,就是在不改变源码的基础上横向扩展一些功能,主要应用场景有事务管理、日志、缓存等等。其实现的关键在于AOP框架自动创建的AOP代理,如图所示↓↓
下面我们就以最经典的转账操作进行事务管理的操作进行演示。
分析转账业务的整体流程:
但为了确保整个过程中有意外发生,就需要在扣钱之前开启事务,在成功收钱之后提交事务,所以此时业务流程就变成了
1. 让我们先创建一个dao,实现基本的扣钱和收钱的操作
public class MoneyDao {
/**
* 扣钱
* @param name
* @param money
*/
public void subMoney(String name, BigDecimal money){
System.out.println(name + "消费了" + money + "元");
}
/**
* 收钱
* @param name
* @param money
*/
public void addMoney(String name, BigDecimal money){
System.out.println(name + "收到了" + money + "元");
}
}
2.定义服务接口
public interface MoneyService {
void transfer(String from, String to, BigDecimal money) ;
}
3.然后创建它的实体类去实现它
public class MoneyServiceImpl implements MoneyService {
private MoneyDao moneyDao = new MoneyDao() ;
//为方便模拟,创建了dao的get和set方法,实际操作中只需自动注入即可
public MoneyDao getMoneyDao() {
return moneyDao;
}
public void setMoneyDao(MoneyDao moneyDao) {
this.moneyDao = moneyDao;
}
/**
* 转账业务
* @param from
* @param to
* @param money
*/
public void transfer(String from, String to, BigDecimal money) {
//转出
moneyDao.subMoney(from,money);
//转入
moneyDao.addMoney(to,money);
}
}
4.动态代理实现功能的嵌入(aop核心)
public class MyFactory {
public static MoneyService getMoneyService(){
final MoneyService service = new MoneyServiceImpl() ;
MoneyDao moneyDao = new MoneyDao() ;
((MoneyServiceImpl) service).setMoneyDao(moneyDao);
MoneyService moneyService = (MoneyService) Proxy.newProxyInstance(MyFactory.class.getClassLoader(), service.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//模拟开启事务
System.out.println("开启事务");
Object invoke = null ;
try{
invoke = method.invoke(service, args);
//模拟提交事务
System.out.println("提交事务");
}finally {
//出现异常回滚事务
System.out.println("回滚事务");
}
return invoke;
}
});
return moneyService ;
}
}
5.创建controller类模拟接收页面参数,并调用服务
public class UserController {
public void transfer(String from, String to, BigDecimal money){
//使用代理类生成service对象,并调用转账方法
MoneyService service = MyFactory.getMoneyService();
service.transfer(from,to,money);
}
}
6.测试(模拟页面传参)
public class TestMain {
public static void main(String[] args) {
UserController userController = new UserController() ;
userController.transfer("张三","李四",new BigDecimal(1000));
}
}