是一种编程思想,通过预编译方式和动态代理实现程序功能的统一维护技术,是spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑的耦合度降低,可以提高程序的可重用性,同时提高开发效率,是OOP思想的扩展。
应用场景:主要使用在对一些公共操作进行统一的处理,例如登录校验、权限控制、统一日志记录、统一返回格式、统一一次处理等。
AOP底层使用的是动态代理,若类为接口实现类,默认使用JDK动态代理,否则使用CGLIB动态代理。
关于代理类的生成时期:
使用AOP实现对用户登录进行校验。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@RequestMapping("/login")
public Object login(HttpServletRequest request){
//生成session
HttpSession session = request.getSession(true);
log.info("用户session生成成功 id:"+session.getId());
return "登录成功";
}
//连接点
@RequestMapping("/udetail")
public Object getUser(HttpServletRequest request){
//验证登录~~~使用AOP
log.info("获取用户详细成功");
return "获取用户详细信息成功";
}
}
/**
* 定义切面,登录拦截
*/
@Component
@Aspect
@Slf4j
public class LoginAOP {
/**
* @Pointcut:定义切点
* 对UserController使用规则
* execution<修饰符>(返回类型 包.类.方法(参数)<异常>)
*/
@Pointcut("execution(* com.example.demo.controller.UserController.getUser(..))")
public void pointCut(){
}
//环绕通知
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint joinPoint){
//判定用户是否登录
log.info("验证用户是否登录中···");
Object[] args = joinPoint.getArgs();
HttpServletRequest request = (HttpServletRequest) args[0];
HttpSession session = request.getSession(false);
if(session == null){
log.info("登录验证失败返回");
return "登录失败";
}
log.info("登录验证成功");
Object obj = null;
try {
//执行目标方法
obj = joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
}
其他通知:@After(前置通知)、@Before(后置通知)、@AterReturning(最终通知)、@AfterThrowing(异常通知)
使用传统的AOP来实现登录校验的功能还是比较繁琐的,为了简化开发,Spring MVC对AOP进行了进一步的封装,产生了拦截器。
使用Spring MVC拦截器的基本规则如下:
@Slf4j
@Component
public class LoginHandler implements HandlerInterceptor {
/**
* preHandle表示在请求到达控制器之前执行
* @param request
* @param response
* @param handler
* @return true:表示不需要拦截控制器的执行,后续执行控制器的业务逻辑;false:表示需要拦截控制器的执行
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession(false);
if(session != null){
log.info("已经登录,运行执行控制层业务逻辑");
return true;
}
//未登录、权限验证失败
log.info("未登录,不允许执行控制层业务逻辑");
response.setStatus(401);
return false;
}
}
/**
* 添加Spring MVC拦截器
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginHandler loginHandler;
/**
* 将拦截器添加到系统配置中
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration interceptorRegistration = registry.addInterceptor(loginHandler);
//添加URL拦截规则,相当于AOP的切点
//拦截所有的URL
interceptorRegistration.addPathPatterns("/**");
//排除某一个URL
interceptorRegistration.excludePathPatterns("/admin/login");
}
}
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(Exception.class)
@ResponseBody
public Object handler(Exception e){
HashMap<String,Object> result = new HashMap<>();
result.put("code","-1");
result.put("message", "异常信息:"+e.getMessage());
return result;
}
}
@ControllerAdvice:用于为Controller提供一些全局的处理。
@ExceptionHandler:@ExceptionHandler注解可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常。
@ControllerAdvice+@ExceptionHandler:表示用于捕获Controller中抛出指定类型的异常,从而达到统一异常的处理。@ResponceBody,表示异常处理后返回的是数据,非视图。
@ControllerAdvice
public class ResultAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//如果结果已经被封装了,就不需要再进行处理了
if(body instanceof HashMap){
return body;
}
//没有则对响应进一步封装
HashMap hashMap = new HashMap();
hashMap.put("status", "1");
hashMap.put("msg", "");
hashMap.put("data",body);
return hashMap;
}
}
@ControllerAdvice+ResponseBodyAdvice接口,表示在Controller执行完成之后,response返回给客户端之前,执行的对response的一些处理,可以实现对response数据的一些统一封装或者加密等操作。
AOP面向切面编程是一种编程思想,和OOP面向对象编程类型,主要实现的功能是对统一功能进行统一处理,提高了代码的复用率(开发效率提示)、业务解耦合。