文章目录
- 前言
- 一、准备
- 1.引入库
- 2. 业务类
- 2.1 service
- 2.2 impl
- 二、核心代码
- 1. 切面类
- 2. 配置类
- 3. 启动类
- 4. 执行结果
- 总结
前言
Spring AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的一个重要模块,它提供了一种将横切关注点(cross-cutting concerns)从业务逻辑中分离出来的方法。横切关注点通常包括日志记录、事务管理、安全性等,这些关注点经常散落在代码的各个角落,导致代码重复和难以维护。
通过使用Spring AOP,你可以将这些横切关注点定义为切面(Aspect),然后将它们织入(weave)到目标对象的方法执行流程中。这样,你可以在不影响业务逻辑的前提下,添加或修改横切关注点的行为。
Spring AOP主要使用代理模式来实现,它为目标对象创建一个代理对象,并在代理对象上拦截方法调用。当方法被调用时,代理对象会根据切面的配置来决定是否执行额外的操作(如日志记录、事务管理等)。
Spring AOP的主要特点包括:
- 声明式编程:你可以通过注解或XML配置文件来声明切面、切点和通知(advice),而无需修改业务代码。
- 集成性强:Spring AOP与Spring的其他模块(如Spring MVC、Spring Data等)无缝集成,可以轻松地在Spring应用中实现面向切面编程。
- 可扩展性:你可以自定义切面、切点和通知的实现,以满足特定的业务需求。
需要注意的是,Spring AOP是基于代理的,因此它只能拦截通过Spring容器管理的bean之间的方法调用。对于非Spring管理的对象或方法(如静态方法、私有方法等),Spring AOP可能无法提供支持。如果需要更强大的AOP功能,可以考虑使用AspectJ等更专业的AOP框架。
一、准备
1.引入库
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
2. 业务类
2.1 service
package org.example.aop.annotation;
/**
* Create by zjg on 2024/4/14
*/
public interface Calculator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i,int j);
int div(int i,int j);
}
2.2 impl
package org.example.aop.annotation.impl;
import org.example.aop.annotation.Calculator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Create by zjg on 2024/4/14
*/
public class CalculatorImpl implements Calculator {
private Logger logger = LoggerFactory.getLogger(CalculatorImpl.class);
@Override
public int add(int i, int j) {
logger.debug("add({},{})",i,j);
// int s=1/0;
return i+j;
}
@Override
public int sub(int i, int j) {
logger.debug("sub({},{})",i,j);
return i-j;
}
@Override
public int mul(int i, int j) {
logger.debug("mul({},{})",i,j);
return i*j;
}
@Override
public int div(int i, int j) {
logger.debug("div({},{})",i,j);
return i/j;
}
}
二、核心代码
1. 切面类
package org.example.aop.annotation.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* Create by zjg on 2024/4/14
*/
@Component
@Aspect
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Pointcut("execution(* org.example.aop.annotation.*.*(..))")
public void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
logger.debug("[{}前置通知]{}",name, Arrays.toString(args));
}
@AfterReturning(value="pointcut()",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
String name = joinPoint.getSignature().getName();
logger.debug("[{}返回通知][{}]",name,result);
}
@AfterThrowing(value="pointcut()",throwing = "exception")
public void afterThrowing(JoinPoint joinPoint,Exception exception){
String name = joinPoint.getSignature().getName();
logger.debug("[{}异常通知][{}]",name,exception.getMessage());
}
@After("pointcut()")
public void after(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
logger.debug("[{}后置通知]",name);
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
logger.debug("[{}环绕通知前置]{}",name,Arrays.toString(args));
Object result = null;
try {
result= joinPoint.proceed();
logger.debug("[{}环绕通知返回][{}]",name,result);
}catch (Exception exception){
logger.debug("[{}环绕通知异常]",name);
}finally {
logger.debug("[{}环绕通知后置]",name);
}
return result;
}
}
2. 配置类
package org.example.aop.annotation.config;
import org.example.aop.annotation.Calculator;
import org.example.aop.annotation.impl.CalculatorImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* Create by zjg on 2024/4/14
*/
@Configuration
@ComponentScan("org.example.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfig {
@Bean
public Calculator calculator(){
return new CalculatorImpl();
}
}
3. 启动类
package org.example.aop.annotation;
import org.example.aop.annotation.config.SpringConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Create by zjg on 2024/4/14
*/
public class SpringApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(SpringConfig.class);
Calculator calculator = acac.getBean("calculator", Calculator.class);
calculator.add(1,1);
}
}
4. 执行结果
[2024-04-14 13:50:14.032][main][DEBUG]- org.example.aop.annotation.aspect.LogAspect.around(LogAspect.java:52) - [add环绕通知前置][1, 1]
[2024-04-14 13:50:14.033][main][DEBUG]- org.example.aop.annotation.aspect.LogAspect.before(LogAspect.java:31) - [add前置通知][1, 1]
[2024-04-14 13:50:14.033][main][DEBUG]- org.example.aop.annotation.impl.CalculatorImpl.add(CalculatorImpl.java:16) - add(1,1)
[2024-04-14 13:50:14.033][main][DEBUG]- org.example.aop.annotation.aspect.LogAspect.afterReturning(LogAspect.java:36) - [add返回通知][2]
[2024-04-14 13:50:14.034][main][DEBUG]- org.example.aop.annotation.aspect.LogAspect.after(LogAspect.java:46) - [add后置通知]
[2024-04-14 13:50:14.034][main][DEBUG]- org.example.aop.annotation.aspect.LogAspect.around(LogAspect.java:56) - [add环绕通知返回][2]
[2024-04-14 13:50:14.034][main][DEBUG]- org.example.aop.annotation.aspect.LogAspect.around(LogAspect.java:60) - [add环绕通知后置]
总结
回到顶部