面试题答案
一键面试1. Spring AOP底层原理
Spring AOP是基于动态代理实现面向切面编程的。动态代理主要有两种方式:JDK动态代理和CGLIB代理。
- JDK动态代理:JDK动态代理是基于接口实现的。如果目标对象实现了至少一个接口,Spring AOP会使用JDK动态代理来创建代理对象。代理对象实现了与目标对象相同的接口,通过InvocationHandler来处理方法调用,在调用目标方法前后插入切面逻辑。
- CGLIB代理:如果目标对象没有实现接口,Spring AOP会使用CGLIB代理。CGLIB通过继承目标类来创建代理对象,生成一个目标类的子类,在子类中重写目标方法,在方法调用前后插入切面逻辑。
2. 关键步骤
定义切面
在Spring中,使用@Aspect
注解来定义一个切面类。例如:
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class LoggingAspect {
// 切面逻辑会写在这里
}
定义切入点
切入点用于指定在哪些方法上应用切面逻辑。使用@Pointcut
注解来定义切入点表达式。例如:
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class LoggingAspect {
@Pointcut("execution(* com.example.demo.service.*.*(..))")
public void serviceMethod() {}
}
上述表达式表示匹配com.example.demo.service
包下所有类的所有方法。
通知类型的选择和使用
- 前置通知(Before Advice):使用
@Before
注解,在目标方法调用前执行。例如:
import org.aspectj.lang.annotation.Before;
@Aspect
public class LoggingAspect {
@Before("serviceMethod()")
public void beforeServiceMethod() {
System.out.println("Before service method is called.");
}
}
- 后置通知(After Advice):使用
@After
注解,无论目标方法是否正常结束或抛出异常,都会在目标方法调用后执行。例如:
import org.aspectj.lang.annotation.After;
@Aspect
public class LoggingAspect {
@After("serviceMethod()")
public void afterServiceMethod() {
System.out.println("After service method is called.");
}
}
- 返回通知(After Returning Advice):使用
@AfterReturning
注解,在目标方法正常返回后执行。例如:
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class LoggingAspect {
@AfterReturning(pointcut = "serviceMethod()", returning = "result")
public void afterReturningServiceMethod(Object result) {
System.out.println("After service method returns with result: " + result);
}
}
- 异常通知(After Throwing Advice):使用
@AfterThrowing
注解,在目标方法抛出异常时执行。例如:
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class LoggingAspect {
@AfterThrowing(pointcut = "serviceMethod()", throwing = "ex")
public void afterThrowingServiceMethod(Exception ex) {
System.out.println("After service method throws an exception: " + ex.getMessage());
}
}
- 环绕通知(Around Advice):使用
@Around
注解,环绕目标方法,提供对目标方法调用的完全控制。例如:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
@Aspect
public class LoggingAspect {
@Around("serviceMethod()")
public Object aroundServiceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before service method is called.");
try {
return joinPoint.proceed();
} finally {
System.out.println("After service method is called.");
}
}
}
要启用Spring AOP,还需要在配置类或application.xml
中开启AspectJ自动代理,例如在配置类中添加@EnableAspectJAutoProxy
注解:
import org.springframework.context.annotation.Configuration;
import org.springframework.aop.aspectj.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}