AOP 也叫面向切片 我们都熟知OOP面向对象,oop主要是封装继承多态,取得了巨大的成功,
而aop则是把系统分解,往里面插入编织的网,中,在spring boot中一个很成功的切面就是@Transactional 能直接了当的实现事务功能,
aop织入方法有3种 本质上就是一个动态代理
- 编译期:在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展编译器,AspectJ就扩展了Java编译器,使用关键字aspect来实现织入;
- 类加载器:在目标类被装载到JVM时,通过一个特殊的类加载器,对目标类的字节码重新“增强”;
- 运行期:目标对象和切面都是普通Java类,通过JVM的动态代理功能或者第三方库实现运行期动态织入。
aop核心概念
- Aspect:切面,即一个横跨多个核心逻辑的功能,或者称之为系统关注点;
- Joinpoint:连接点,即定义在应用程序流程的何处插入切面的执行;
- Pointcut:切入点,即一组连接点的集合;
- Advice:增强,指特定连接点上执行的动作;
- Introduction:引介,指为一个已有的Java对象动态地增加新的接口;
- Weaving:织入,指将切面整合到程序的执行流程中;
- Interceptor:拦截器,是一种实现增强的方式;
- Target Object:目标对象,即真正执行业务的核心逻辑对象;
- AOP Proxy:AOP代理,是客户端持有的增强后的对象引用。
接下来我们来自定义一个注解
1.首先创建一个注解类
/**
*
* 自定义注解
* 注解的声明:public @interface 注解名称
*
* 元注解:标记注解的注解
* @Documented:表示该注解会被javadoc命令写入api文档中
* @Target:注解的标记位置
* ElementType.ANNOTATION_TYPE:该注解可以标记别的注解
* ElementType.CONSTRUCTOR:标注到构造方法
* ElementType.FIELD:标注到成员属性
* ElementType.LOCAL_VARIABLE:标注到局部变量
* ElementType.METHOD:标注到方法上
* ElementType.PACKAGE:标注到包上
* ElementType.PARAMETER:标注到方法形参上
* ElementType.TYPE:标注到类、接口、枚举类上
* @Retention:注解的作用范围
* RetentionPolicy.SOURCE:注解的有效范围只在源码中,编译后就被丢弃
* RetentionPolicy.CLASS:注解有效范围在编译文件中,运行时丢弃
* RetentionPolicy.RUNTIME:注解在运行时仍然有效,这个范围的注解可以通过反射获取
*
* 注解内的方法声明:
* 类型 方法名() [defualt 默认值];
*
* 注意:
* 如果一个属性没有设置default默认值,在标记这个注解时,必须给定该属性值
* 如果一个属性的名字为value,则在赋值时可以省略属性名。当如果需要赋值两个以上的属性,则value不能省略
* 如果一个属性的类型是数组类型,则应该用{}赋值,如果只要给一个值,{}可以省略
/**
* @author Bruce
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cs {
boolean data () default false;
}
2.我们来创建一个切片@Aspect
package com.example.demo.config;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* @author Bruce
*/
@Component
@Aspect
public class Csa {
@Around(value="execution(* *..*Controller.*(..)) && @annotation(cs)")
public Object check(ProceedingJoinPoint pjp,Cs cs) throws Throwable {
System.out.println(cs.data());
Object ret = pjp.proceed();
long begin = System.currentTimeMillis();
String method = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().getName();
log.info("Aspect = [{}] ,class [{}] , method [{}] , time consuming[{}]", new Date(), className, method, System.currentTimeMillis() - begin);
return ret;
}
}
这样就能控制到所有的带cs注释的controller
3.给controller添加注释
/**
* 测试
* */
@Cs
@RequestMapping(value="/userTest", method = RequestMethod.GET)
public String test() {
return IdGenerator.getNextId().toString();
}
一个简单的自定义注解就完成了