05-AOP的实际应用场景

AOP的实际案例

事务控制

在一个业务流程当中,可能需要多条DML语句共同完成,所以为了保证数据的安全需要添加事务控制的代码保证多条DML语句同时成功或失败

  • 业务类中的每一个业务方法控制事务的代码格式基本是固定的,我们可以采用AOP思想将这些交叉业务代码抽取出来,这样代码既能复用又易维护
class 业务类1{
    public void 业务方法1(){
        try{
            // 开启事务
            startTransaction();
            
            // 执行核心业务逻辑
            step1();
            step2();
            step3();
            ....
            
            // 提交事务
            commitTransaction();
        }catch(Exception e){
            // 回滚事务
            rollbackTransaction();
        }
    }
    
    public void 业务方法2(){
        try{
            // 开启事务
            startTransaction();
            
            // 执行核心业务逻辑
            step1();
            step2();
            step3();
            ....
            
            // 提交事务
            commitTransaction();
        }catch(Exception e){
            // 回滚事务
            rollbackTransaction();
        }
    }
}

class 业务类2{
    public void 业务方法1(){
        try{
            // 开启事务
            startTransaction();
            
            // 执行核心业务逻辑
            step1();
            step2();
            step3();
            ....
            
            // 提交事务
            commitTransaction();
        }catch(Exception e){
            // 回滚事务
            rollbackTransaction();
        }
    }
}
//......

第一步: 定义两个业务类(目标类)AccountService和OrderService以及业务方法(目标方法)

// 订单相关的业务类
@Service
public class OrderService {
    // 生成订单方法
    public void generate(){
        System.out.println("正在生成订单");
    }
    // 取消订单方法
    public void cancel(){
        System.out.println("正在取消订单");
    }
}

// 银行转账相关的业务类
@Service
public class AccountService {
    // 转账业务方法
    public void transfer(){
        System.out.println("正在进行银行账户转账");
    }
    // 取款业务方法
    public void withdraw(){
        System.out.println("正在进行取款操作");
    }
}

第二步: 定义一个事务相关的切面类TransactionAspect,把控制事务的代码写到环绕通知的方法中,根据切点表达式将通知切入到指定业务类的业务方法当中

@Component
@Aspect
public class TransactionAspect { // 事务切面类    
    @Around("execution(* com.powernode.spring6.service..*(..))")// 环绕通知
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        // 控制事务的代码
        try {
            // 前环绕
            System.out.println("开启事务");
            // 执行目标对象的目标方法
            proceedingJoinPoint.proceed();
            // 后环绕	
            System.out.println("提交事务");
        } catch (Throwable e) {
            System.out.println("回滚事务");
        }
    }
}

第三步: 在spring的配置文件开启组件扫描和自动代理

<?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: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.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.powernode.spring6.service"/>
    <!--开启自动代理,spring容器在扫描类的时候会查看该类上是否有@Aspect注解,如果有则给这个切面类生成代理对象-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

第四步: 执行业务类的业务方法,查看环绕通知中的事务控制代码的执行情况

public class AOPTest2 {
    @Test
    public void testTransaction(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class);
        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        // 执行orderService生成订单的方法
        orderService.generate();
        // 执行orderService取消订单的方法
        orderService.cancel();
        // 执行accountService转账的方法
        accountService.transfer();
        // 执行accountService取款的方法
        accountService.withdraw();
    }
}
开启事务
正在生成订单
提交事务

开启事务
正在取消订单
提交事务

开启事务
正在进行银行账户转账
提交事务

开启事务
正在进行取款操作
提交事务

安全日志

需求: 因为增删改操作是属于危险行为, 所以项目上线后凡是在系统中进行增删改操作的用户我们都需要记录下来

第一步: 定义业务类(目标类)UserServiceProductService及其业务方法(目标方法)

// 用户业务类
@Service
public class UserService {
    public void getUser(){
        System.out.println("获取用户信息");
    }
    public void saveUser(){
        System.out.println("保存用户");
    }
    public void deleteUser(){
        System.out.println("删除用户");
    }
    public void modifyUser(){
        System.out.println("修改用户");
    }
}
// 商户业务类
@Service
public class ProductService {
    public void getProduct(){
        System.out.println("获取商品信息");
    }
    public void saveProduct(){
        System.out.println("保存商品");
    }
    public void deleteProduct(){
        System.out.println("删除商品");
    }
    public void modifyProduct(){
        System.out.println("修改商品");
    }
}

第二步: 定义一个负责安全的切面类SecurityAspect,把记录安全日志的代码写到通知的方法中,根据切点表达式将通知切入到指定业务类的业务方法当中

@Component
@Aspect
public class SecurityAspect {
    // 抽取可重用的切点表达式
    @Pointcut("execution(* com.powernode.spring6.biz..save*(..))")
    public void savePointcut(){}

    @Pointcut("execution(* com.powernode.spring6.biz..delete*(..))")
    public void deletePointcut(){}

    @Pointcut("execution(* com.powernode.spring6.biz..modify*(..))")
    public void modifyPointcut(){}
	// 使用抽取好的切点表达式,指定通知只作用于增删改的方法
    @Before("savePointcut() || deletePointcut() || modifyPointcut()")
    public void beforeAdivce(JoinPoint joinpoint){
        System.out.println("XXX操作员正在操作"+joinpoint.getSignature().getName()+"方法");
    }
}

第三步: 在spring的配置文件开启组件扫描和自动代理

<?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: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.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启组件扫描,biz也是业务层-->
    <context:component-scan base-package="com.powernode.spring6.biz"/>
    <!--开启自动代理,spring容器在扫描类的时候会查看该类上是否有@Aspect注解,如果有则给这个切面类生成代理对象-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

第四步: 执行业务类的业务方法,查看前置通知中记录安全日志的代码的执行情况

@Test
public void testSecurity(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class);
    UserService userService = applicationContext.getBean("userService", UserService.class);
    ProductService productService = applicationContext.getBean("productService", ProductService.class);
    // 调用userService对象的增删改查方法
    userService.getUser();
    userService.saveUser();
    userService.deleteUser();
    userService.modifyUser();
    
    // 调用productService对象的增删改查方法
    productService.getProduct();
    productService.saveProduct();
    productService.deleteProduct();
    productService.modifyProduct();
}
获取用户信息
XXX操作员正在操作saveUser方法
保存用户
XXX操作员正在操作deleteUser方法
删除用户
XXX操作员正在操作modifyUser方法
修改用户

获取商品信息
XXX操作员正在操作saveProduct方法
保存商品
XXX操作员正在操作deLeteProduct方法
删除商品
XXX操作员正在操作modifyProduct方法
修改商品
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值