聊聊: 在开发中经常会碰到 日志记录、权限检查、事务控制 等问题,如果全都手动进行编码,代码量将会非常夸张,不符合 DRY 原则,也不遵循开闭原则,或者通过封装等方式简化代码,依旧不遵循开闭原则,也为后期维护增加压力。这个时候就可以使用 AOP 的思想了。
概念
AOP 是一种面向切面编程的思想,大概可以理解为,把与业务逻辑无关的操作分离出来。举个例子:把一块面包切成几段,每段之间加了一些好吃夹层,增加了口感又不影响原有的面包分量。
常用AOP框架 AspectJ
//定义切面类
@Aspect
public class Test {
/** @Pointcut 有多种使用方式
* - 方式一: @annotation: 当执行的方法上拥有指定的注解时生效
* - 例: @annotation(xx.xx.annotation.TestAnno)
* - 方式二: execution: 匹配指定范围的方法
* - 注意: 第一个 * 后面要有空格
* - 例: execution(* xx.xx.service.impl.*ServiceImpl.*(..))
* - 方式三: @within(适用于注解范围固定的情况): 当执行的类上拥有执行的注解时生效
* - 例: @within(xx.xx.annotation.TestAnno)
*/
//第一个 * 后面要有空格
@Pointcut("@annotation(xx.xx.annotation.TestAnno)")
public void txPointcut() {}
//前置通知
@Before("txPointcut()")
public void test01() {
System.out.println("test01");
}
//返回之后通知
@AfterReturning("txPointcut()")
public void test02() {
System.out.println("test02");
}
//抛出(异常)后执⾏通知
@AfterThrowing("txPointcut()")
public void test03() {
System.out.println("test03");
}
//后置通知
@After("txPointcut()")
public void test04() {
System.out.println("test04");
}
//围绕通知
@Around("txPointcut()")
public void test05() {
System.out.println("test05");
}
}
定义注解
// 语法格式
元注解
修饰符 @interface 注解名 {
// 成员(属性)
返回值类型 方法名() default 默认值
}
1.元注解
-
@Target: 表示注解可以贴在哪些位置(类,方法上,构造器上等等)
-
@Retention: 用于描述注解的生命周期
-
@Documented: 使用 @Documented 标注的标签会保存到 API文档中.
-
@Inherited: @Inherited标注的标签可以被子类所继承.
2.示例代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy=RUNTIME)
@Inherited
@interface A{ }
@A
class Merchandise{ }
3.返回值类型
只能是八种基本数据类型、String
类型、
Class
类型、
enum
类型、
Annotation
类型、以上所有
类型的数组
4.拓展
- getAnnotation( Class clz ):通过类的Class对象调用该方法,参数使用注解的class,可以拿到类中关于注解的相关信息
示例代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Content {
public String value() default "hello world";
}
import com.wwx.web.util.Content;
import lombok.Data;
@Data
@Content
//商户
public class Merchandise {
//编号
private Integer goodsId;
//名称
private String name;
//数量
private Integer number;
}
@GetMapping("/anno")
public String test(){
Merchandise merchandise = new Merchandise();
Class<? extends Merchandise> merchandiseClass = merchandise.getClass();
Content content = merchandiseClass.getAnnotation(Content.class);
return content.value();
}