AOP (Aspect Oriented Programming) 是另一个核心概念。它是一种程序设计的方法,允许程序员将横切关注点(如日志记录、性能监测等)区别于业务逻辑代码,并通过将它们独立地定义为切面来实现。在Spring框架中,AOP可以通过使用注解或XML配置来实现。
Spring中的AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,用于处理那些在各个组件中经常出现的交叉关注点(cross-cutting concerns),比如日志记录、事务管理、安全性等。AOP使得这些关注点可以在合适的时机、以适当的方式被引入到程序中,而无需修改原有代码。
AOP 背后的原理
暂时不学
定义一个切面类:
import org.aspectj.lang.annotation.*;
@Aspect
public class LoggingAspect {
@Before("execution(* com.example.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
@After("execution(* com.example.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature().getName());
}
@Around("execution(* com.example.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("Method executed in " + (endTime - startTime) + " ms");
return result;
}
}
在Spring配置文件中开启AOP支持:
<aop:aspectj-autoproxy />
定义一个目标类:
import org.springframework.stereotype.Component;
@Component
public class MyService {
public String doSomething() {
// some logic here...
return "result";
}
}
在这个例子中,LoggingAspect定义了一个切面类,它包含三个通知:logBefore、logAfter和logAround。@Before和@After注解表示在com.example包下所有类的所有方法执行前和执行后分别打印日志。@Around注解表示在com.example包下所有类的所有方法执行时打印方法的执行时间。最后,我们在Spring配置文件中开启了对AspectJ的支持,并定义了一个目标类MyService。当我们在应用中使用MyService时,就会自动应用LoggingAspect中定义的通知逻辑。
例如,我们可以在一个方法执行前后分别记录日志和执行事务管理操作。如果我们使用面向切面编程,则可以将这些操作作为一个切面(Aspect)定义出来,并在方法执行前后自动执行这些操作。这样我们就可以避免在每个方法中都重复编写这些代码,从而提高代码的可维护性和可读性。
@Aspect
public class LoggingAspect {
@Before("execution(public * com.example.demo.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
@After("execution(public * com.example.demo.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature().getName());
}
}
在上述代码中,我们创建了一个名为LoggingAspect的切面类,并通过@Aspect注解进行标记。然后,我们定义了两个方法logBefore和logAfter,它们分别在目标方法执行前和执行后被调用。通过使用@Before和@After注解,我们可以指定这些方法在哪些目标方法执行前或执行后被调用。在本例中,我们使用了通配符来指定所有位于com.example.demo.service包下的类的所有公共方法。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="loggingAspect" class="com.example.demo.aspects.LoggingAspect"/>
<aop:config>
<aop:aspect ref="loggingAspect">
<aop:before method="logBefore" pointcut="execution(public * com.example.demo.service.*.*(..))"/>
<aop:after method="logAfter" pointcut="execution(public * com.example.demo.service.*.*(..))"/>
aop:aspect>
aop:config>
beans>
在上述代码中,我们通过使用
元素来创建LoggingAspect类的实例,并使用
元素来启用AOP支持。然后,我们使用
元素来指定切面类,并使用
和
元素来定义切面方法的目标方法在执行前和执行后被调用。在本例中,我们使用了与切面类中相同的pointcut表达式来指定目标方法。