AOP切面的用途

目录

  • 1.切面的用途
    • 1.1正常创建切面类
  • 2.切面可以用于以下常见的场景:
    • 2.1 日志记录:
    • 2.2性能统计:
    • 2.3 安全控制和权限管理:
    • 2.4 事务处理:
    • 2.5 异常处理:
    • 2.6资源池管理:
  • 3.详细业务举例

1.切面的用途

日志记录,性能统计,安全控制,权限管理,事务处理,异常处理,资源池管理。

1.1正常创建切面类

package com.example.demo.aop;

import com.example.demo.model.SysLog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {
//    @Autowired
//    private SysLog sysLog;
		
@Pointcut("@annotation(com.springboot.annotation.Log)")表示在被@Log注解标记的方法上进行拦截。
    @Pointcut("@annotation(com.example.demo.annotation.Log)")
    public void pointcut() {

    }
    @Around("(pointcut())")
    public void around(ProceedingJoinPoint point) {
        long beginTime = System.currentTimeMillis();
        try {
            // 执行方法
            point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日志
        System.out.println("执行的方法"+point.getSignature().getName());
        System.out.println("执行的时间"+time);
//        sysLog.setId(11);
//        System.out.println(sysLog);
    }
    

}

2.切面可以用于以下常见的场景:

当使用切面编程时,切面可以用于以下常见的场景:

2.1 日志记录:

切面可以用来记录应用程序的运行日志,例如记录方法的调用、参数信息、返回值等。以下是一个使用切面记录日志的示例代码:

@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Before executing method: " + methodName);
    }
    
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("After executing method: " + methodName);
        System.out.println("Method returned: " + result);
    }
}

2.2性能统计:

切面可以用于统计方法的执行时间,帮助我们找出应用程序中的性能瓶颈。以下是一个使用切面进行性能统计的示例代码:

@Aspect
@Component
public class PerformanceAspect {

    @Around("execution(* com.example.service.*.*(..))")
    public Object measurePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;
        
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Method " + methodName + " execution time: " + executionTime + "ms");
        
        return result;
    }
}

2.3 安全控制和权限管理:

切面可以用于实现安全控制和权限管理,例如检查用户是否具有执行某个方法的权限。以下是一个使用切面进行权限管理的示例代码:

@Aspect
@Component
public class SecurityAspect {

    @Before("@annotation(com.example.annotation.RequiresPermission)")
    public void checkPermission(JoinPoint joinPoint) {
        // 检查用户是否具有执行该方法的权限
        // 如果没有权限,可以抛出异常或进行其他处理
    }
}

2.4 事务处理:

切面可以用于实现事务处理,例如在方法执行前开启事务,在方法执行后提交或回滚事务。以下是一个使用切面进行事务处理的示例代码:

@Aspect
@Component
public class TransactionAspect {
    
    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        // 开启事务
        // 执行方法
        // 提交或回滚事务
    }
}

2.5 异常处理:

切面可以用于统一处理方法中的异常,例如记录日志、发送通知或进行其他异常处理操作。以下是一个使用切面进行异常处理的示例代码:

@Aspect
@Component
public class ExceptionAspect {

    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
    public void handleException(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Exception occurred in method: " + methodName);
        System.out.println("Exception message: " + ex.getMessage());
        // 其他异常处理操作
    }
}

2.6资源池管理:

切面可以用于管理资源池,例如连接池、线程池等。以下是一个使用切面管理资源池的示例代码:

@Aspect
@Component
public class ResourcePoolAspect {

    @Around("@annotation(com.example.annotation.ResourcePool)")
    public Object manageResourcePool(ProceedingJoinPoint joinPoint) throws Throwable {
        // 从资源池中获取资源
        // 执行方法
        // 将资源归还到资源池
    }
}

切面编程的灵活性和可定制性使得我们能够根据实际情况将其应用于各种不同的场景中。

3.详细业务举例

  1. 日志记录:
    假设我们有一个用户管理系统,其中包含一个UserService服务类,它提供了一些方法来管理用户。我们可以使用切面记录每个方法的调用情况和返回值,以便跟踪问题和排除错误。以下是示例代码:
@Service
public class UserService {
    
    public void createUser(User user) {
        // 创建用户
    }

    public User getUserById(long id) {
        // 根据ID获取用户
        return null;
    }
    
    // 其他方法...
}
@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.UserService.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Before executing method: " + methodName);
    }
    
    @AfterReturning(pointcut = "execution(* com.example.service.UserService.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("After executing method: " + methodName);
        System.out.println("Method returned: " + result);
    }
}

例如,当我们调用createUser方法时,日志输出可能如下所示:

Before executing method: createUser
After executing method: createUser
Method returned: null
  1. 性能统计:
    假设我们有一个订单管理系统,其中包含一个OrderService服务类,它提供了一些方法来管理订单。我们可以使用切面记录每个方法的执行时间,以便找出性能瓶颈并进行优化。以下是示例代码:
@Service
public class OrderService {
    
    public List<Order> getOrdersByUserId(long userId) {
        // 根据用户ID获取订单列表
        return null;
    }

    public void createOrder(Order order) {
        // 创建订单
    }
    
    // 其他方法...
}
@Aspect
@Component
public class PerformanceAspect {

    @Around("execution(* com.example.service.OrderService.*(..))")
    public Object measurePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;
        
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Method " + methodName + " execution time: " + executionTime + "ms");
        
        return result;
    }
}

例如,当我们调用getOrdersByUserId方法时,控制台输出可能如下所示:

Method getOrdersByUserId execution time: 10ms
  1. 安全控制和权限管理:
    假设我们有一个文章发布系统,其中包含一个ArticleService服务类,它提供了一些方法来管理文章。我们可以使用切面检查用户是否具有执行某个方法的权限,以保护敏感信息。以下是示例代码:
@Service
public class ArticleService {
    
    @RequiresPermission("article.create")
    public void createArticle(Article article) {
        // 创建文章
    }

    @RequiresPermission("article.view")
    public Article getArticleById(long id) {
        // 根据ID获取文章
        return null;
    }
    
    // 其他方法...
}
@Aspect
@Component
public class SecurityAspect {

    @Before("@annotation(com.example.annotation.RequiresPermission)")
    public void checkPermission(JoinPoint joinPoint) {
        // 检查用户是否具有执行该方法的权限
        // 如果没有权限,可以抛出异常或进行其他处理
        String permission = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        if (!hasPermission(permission)) {
            throw new SecurityException("Permission denied for method: " + permission);
        }
    }
    
    private boolean hasPermission(String permission) {
        // 检查当前用户是否具有指定权限
        // 实际实现中可能需要从数据库或缓存中获取权限列表,并进行校验
        return true;
    }
}

例如,当我们调用createArticle方法时,并且当前用户没有article.create权限时,将会抛出SecurityException异常。

  1. 事务处理:
    假设我们有一个银行系统,其中包含一个AccountService服务类,它提供了一些方法来管理账户。我们可以使用切面在方法执行前开启事务,在方法执行后提交或回滚事务,以保证数据完整性和一致性。以下是示例代码:
@Service
@Transactional
public class AccountService {
    
    public void transferMoney(long fromAccountId, long toAccountId, double amount) {
        // 从一个账户向另一个账户转账
    }

    public void withdrawMoney(long accountId, double amount) {
        // 从一个账户取款
    }
    
    // 其他方法...
}
@Aspect
@Component
public class TransactionAspect {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(definition);
        
        try {
            Object result = joinPoint.proceed();
            transactionManager.commit(status);
            return result;
        } catch (Throwable ex) {
            transactionManager.rollback(status);
            throw ex;
        }
    }
}
  1. 异常处理:
    假设我们有一个邮件发送系统,其中包含一个MailService服务类,它提供了一些方法来发送邮件。我们可以使用切面统一处理方法中的异常,例如记录日志、发送通知或进行其他异常处理操作。以下是示例代码:
@Service
public class MailService {
    
    public void sendMail(Mail mail) {
        // 发送邮件
    }

    public void deleteMail(long id) {
        // 根据ID删除邮件
        throw new RuntimeException("Unable to delete mail: " + id);
    }
    
    // 其他方法...
}
@Aspect
@Component
public class ExceptionAspect {

    @AfterThrowing(pointcut = "execution(* com.example.service.MailService.*(..))", throwing = "ex")
    public void handleException(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Exception occurred in method: " + methodName);
        System.out.println("Exception message: " + ex.getMessage());
        // 其他异常处理操作,例如记录日志、发送通知等
    }
}

例如,当我们调用deleteMail方法时,并且出现了运行时异常时,控制台输出可能如下所示:

Exception occurred in method: deleteMail
Exception message: Unable to delete mail: 123

你可能感兴趣的:(Java,java,spring,aop)