什么是AOP?
* AOP为Aspect Oriented Programming的缩写,意为:面向切面编程
* AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
* AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
* 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
* AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
* 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
- AOP的作用及优势是什么?
- 作用:
- AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
- 在程序运行期间,不修改源码对已有方法进行增强
- 将业务逻辑和系统处理的代码(关闭连接、事务管理、操作日志记录)解耦
- 优势:
- 减少重复代码
- 提高开发效率
- 维护方便
- 作用:
- AOP相关术语介绍
-
1. Joinpoint(连接点) -- 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
2. Pointcut(切入点) -- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
3. Advice(通知/增强) -- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
4. Introduction(引介) -- 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field
5. Target(目标对象) -- 代理的目标对象
6. Weaving(织入) -- 是指把增强应用到目标对象来创建新的代理对象的过程
7. Proxy(代理) -- 一个类被AOP织入增强后,就产生一个结果代理类
8. Aspect(切面) -- 是切入点和通知的结合,以后咱们自己来编写和配置的
-
以上内容摘自Spring AOP文档!
源码示例:
1.自定义注解:
package com.example.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
String remark() default "";
String type() default "QUERY";
}
2.切面编程:
package com.example.demo.aspect;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component //加入到spring容器
@Aspect //切面
public class AspectDemo {
/**
* 方法用途(切入点表达式可以用&&,||,!来组合使用):
* execution: 匹配连接点:execution(* com.example.demo.*(..))--com.example.demo包下所有类的方法
* within: 某个类里面
* this: 指定AOP代理类的类型
* target:指定目标对象的类型
* args: 指定参数的类型
* bean:指定特定的bean名称,可以使用通配符(Spring自带的)
* @target: 带有指定注解的类型
* @args: 指定运行时传的参数带有指定的注解
* @within: 匹配使用指定注解的类
* @annotation:指定方法所应用的注解
* <br/>
* 操作步骤: TODO<br/>
* ${tags}
*/
@Pointcut("@annotation(com.example.demo.annotation.AnnotationDemo)")
public void asAnnotation() {}
/**
* 方法用途:
* 在AnnotationDemo注解之前执行
* 标识一个前置增强方法,相当于BeforeAdvice的功能.
* <br/>
* 操作步骤: TODO<br/>
* ${tags}
*/
@Before("asAnnotation()")
public void beforeRun() {
System.out.println("在AnnotationDemo注解之前执行");
}
/**
* 方法用途:
* @Around 环绕增强,相当于MethodInterceptor,对带@AnnotationDemo注解的方法进行切面,并获取到注解的属性值
* ProceedingJoinPoint: 环绕通知
* <br/>
* 操作步骤: TODO<br/>
* ${tags}
*/
@Around("asAnnotation() && @annotation(annotationDemo)")
public Object around(ProceedingJoinPoint joinPoint,AnnotationDemo annotationDemo) {
Object obj = null;
try {
// AnnotationDemo注解的属性值
annotationDemo.remark();
Object[] args = joinPoint.getArgs();
String arg = JSON.toJSONString(args);
System.out.println("请求参数:"+ arg);
Signature signature = joinPoint.getSignature();
// 方法package路径
String methodUrl = signature.getDeclaringTypeName();
// 方法名,不包含package路径
String method = signature.getName();
System.out.println("正在执行" + method + "方法,路径:" + methodUrl);
// obj是返回的结果,joinPoint.proceed用于启动目标方法执行,非常重要
obj = joinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("切面执行");
return obj;
}
/**
* 方法用途:
* 在AnnotationDemo注解之后执行
* final增强,不管是抛出异常或者正常退出都会执行。
* @AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
* @AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
* <br/>
* 操作步骤: TODO<br/>
* ${tags}
*/
@AfterReturning(returning = "obj", Pointcut = "asAnnotation()")
public void after(Object obj) {
System.out.println("在AnnotationDemo注解之后执行");
logger.info("执行成功,Result:{}", JSON.toJsonString(obj));
}
}
Service代码:
public interface UserService {
/**
* 方法用途: 根据userId查询用户信息<br/>
* 操作步骤: TODO<br/>
* ${tags}
*/
UserEntity getUser(Map<String, Object> map);
}
Service实现类:
package com.example.demo.service.impl;
import com.example.demo.entity.UserEntity;
import com.example.demo.reflect.ReflectUtil;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Override
public UserEntity getUser(Map<String, Object> map) {
// ReflectUtil在上一篇Java反射机制已经实现了,不懂的请查看:https://blog.csdn.net/MrQin1/article/details/96486851
return (UserEntity) ReflectUtil.getObject(UserEntity.class, map);
}
}
Controller代码:
package com.example.demo.controller;
import com.example.demo.annotation.AnnotationDemo;
import com.example.demo.entity.UserEntity;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@AnnotationDemo(remark = "根据userId查询用户信息")
@PostMapping("/getUser")
public UserEntity getUser() {
Map<String, Object> map = new HashMap<>();
map.put("userId", 110);
map.put("userName", "张三丰");
map.put("userSex", "man");
map.put("userAge", 99);
UserEntity userEntity = userService.getUser(map);
return userEntity;
}
}