Spring Boot 自定义注解实现AOP切面织入

本文介绍了Spring Boot中AOP的概念,包括动态代理的原理,JDK和CGLIB的区别,以及自定义注解和配置AOP切面的方法。AOP常用于日志记录、权限控制等场景。文中通过一个自定义的日志打印注解示例,展示了如何在控制器方法上添加注解以实现切面功能,并讨论了如何根据环境指定切面的生效条件。
摘要由CSDN通过智能技术生成

AOP简要概述

AOP:
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式或运行时动态代理实现程序功能增强的一种技术,如在方法执行前、或执行后、或是在执行中出现异常后这些地方进行拦截处理或叫做增强处理。AOP现有两个主要的流行框架,即Spring AOP和Spring + AspectJ。
两者的不同
Spring AOP:
1、采用的是动态织入,基于动态代理来实现,默认如果被代理的类实现一个接口,用JDK提供的动态代理实现,如果没有则使用CGLIB实现。
2、Spring AOP需要依赖IOC容器来管理,并且只能作用于Spring容器,使用纯Java代码实现
3、在性能上,由于Spring AOP是基于动态代理来实现的,在容器启动时需要生成代理实例,在方法调用上也会增加栈的深度,使得Spring AOP的性能不如AspectJ的那么好
AspectJ:
1、是静态织入,指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了,所以说它生成的类是没有额外运行时开销的。
(有如下几个织入的时机:)
​ 1、编译期织入(Compile-time weaving): 如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
​ 2、编译后织入(Post-compile weaving): 也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
​3、类加载后织入(Load-time weaving): 指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。

现在Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比 Spring AOP 快很多。

动态代理:
所谓的动态代理就是说AOP框架不会去改动原有代码,而是在内存中临时为方法生成一个AOP对象,这个对象在特定的切点做了增强处理。Spring AOP中的动态代理主要有两种实现方式,JDK动态代理和CGLIB动态代理。
JDK动态代理:
通过反射来接收被代理的类,并且要求被代理的类实现一个接口,它的核心是InvocationHandler接口和Proxy类。如果被代理类没有实现接口,那么Spring AOP就会选择使用CGLIB来动态代理目标类。
CGLIB(Code Generation Library):
是一个代码生成的类库,可以在运行时动态地生成某个类的子类,它是通过继承的方式做的动态代理,因此如果某个类被标记为final(无法被继承),那么它是无法使用CGLIB做动态代理的。
AOP常用使用场景:
日志记录、性能统计、权限控制、事务处理、异常处理、懒加载

自定义注解annotation

一些元注解的说明:

@Retention: 什么时候使用该注解,我们定义为运行时;

  • SOURCE, 编译器处理完该注解后不存储在class中
  • CLASS, 编译器把该注解存储在class字节码文件中
  • RUNTIME, 编译器把该注解存储在class字节码文件中,并且可以由JVM读取,在运行时可以通过反射获取到

@Target: 注解用于什么地方,我们定义为作用于方法和类上;

  • @Target(ElementType.TYPE) //接口、类、枚举、注解
  • @Target(ElementType.METHOD) //方法上
  • @Target(ElementType.FIELD) //字段、枚举的常量
  • @Target(ElementType.PARAMETER) //方法参数
  • @Target(ElementType.CONSTRUCTOR) //构造函数
  • @Target(ElementType.LOCAL_VARIABLE) //局部变量
  • @Target(ElementType.ANNOTATION_TYPE) //注解
  • @Target(ElementType.PACKAGE) ///包

@Documented: 这个Annotation可以被写入javadoc;

@Inherited: 这个Annotation 可以被继承,如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

自定义一个用于日志打印的注解

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({
   Element
  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值