重庆网站seo方法,微信商城开发报价,建网站英语,上海住房建设部官方网站aop#x1f693;AOP 分类AspectJ | 高级但是难用Spring AOP | 易用但仅支持方法aop 原理明月几时有#xff0c;把酒问青天。——唐代李白《将进酒》 AOP 分类
在 Spring Boot 中#xff0c;AOP 的实现主要有以下几种#xff1a; 基于 AspectJ 的 AOP#xff1a;这是一种基…
aopAOP 分类AspectJ | 高级但是难用Spring AOP | 易用但仅支持方法aop 原理明月几时有把酒问青天。——唐代李白《将进酒》 AOP 分类
在 Spring Boot 中AOP 的实现主要有以下几种 基于 AspectJ 的 AOP这是一种基于 Java 语言扩展Java Language ExtensionJLE的 AOP 实现方式支持静态织入和动态织入两种方式。 Spring AOP这是 Spring 框架自带的 AOP 实现方式基于动态代理机制实现只支持方法级别的切面。 自定义注解实现 AOP通过自定义注解和 AOP 技术实现业务逻辑和切面逻辑的分离便于代码的维护和扩展。
其中基于 AspectJ 的 AOP 功能最为强大但使用难度较大Spring AOP 简单易用但功能有一定限制自定义注解实现 AOP 灵活性较高但需要自行实现 AOP 切面逻辑。在实际开发中应根据项目需要选择合适的 AOP 实现方式。 Spring AOP 是基于代理的 AOP而 AspectJ 是基于字节码的 AOP Spring AOP 和 AspectJ 都是 Spring Framework 中的 AOP 实现方式。Spring AOP 是基于代理的 AOP而 AspectJ 是基于字节码的 AOP。
在 Spring Boot 中默认情况下使用的是 Spring AOP。如果需要使用 可以通过在启动类上添加 EnableAspectJAutoProxy(proxyTargetClass true) 注解来开启。
如果需要使用 AspectJ, 需要引入 AspectJ jar包 EnableAspectJAutoProxy 不是用来开启 AspectJ 的吗 配置 EnableAspectJAutoProxy, 不引入 AspectJ jar包的情况下就使用 Spring AOP
EnableAspectJAutoProxy 注解可以用来开启 AspectJ 的支持但是它也是用来开启 Spring AOP 的。
在 Spring 中Spring AOP 和 AspectJ 都是实现 AOP 的方式之一。EnableAspectJAutoProxy 注解用来开启 Spring AOP 的支持如果在注解中设置 proxyTargetClasstrue则会使用 CGLIB 来创建代理对象否则会使用 JDK 的动态代理。
当然在 Spring Boot 中如果需要使用 AspectJ也可以在启动类上添加 EnableAspectJAutoProxy(proxyTargetClass true) 注解来开启 AspectJ 支持
AspectJ | 高级但是难用 AspectJ中的静态织入和动态织入 AspectJ 是一个基于 Java 语言的切面编程框架它提供了两种切面织入方式静态织入和动态织入。
静态织入是指在编译期间将切面代码织入到目标类中生成一个新的字节码文件。在运行期间JVM 加载这个字节码文件并且这个字节码文件包含了目标类和切面代码从而实现对目标类的增强。静态织入的优点是织入后的代码执行效率高缺点是需要在编译期间进行织入增加了额外的工作量和复杂度。
动态织入是指在运行期间将切面代码织入到目标类中不需要在编译期间进行修改。在运行期间通过 JVM 提供的动态代理技术或字节码生成技术将切面代码织入到目标类中从而实现对目标类的增强。动态织入的优点是织入更加灵活可以在运行期间进行修改缺点是织入后的代码执行效率相对较低。
在 AspectJ 中静态织入和动态织入可以通过不同的方式实现。静态织入可以使用 AspectJ 编译器将切面代码编译成字节码文件并将其与目标类一起打包成一个 jar 包或 war 包从而在运行期间加载这个包实现对目标类的增强。动态织入可以使用 AspectJ 提供的 Runtime 织入功能或者使用 Spring AOP 框架提供的动态代理技术实现对目标类的增强。
AspectJ 支持更加灵活的切面编程可以拦截不仅仅是方法级别的切面还可以拦截字段、构造方法、类等级别的切面。
字段级别
要拦截字段级别的切面可以使用 AspectJ 提供的 field 切点匹配器例如
javaCopy code
Aspect
public class FieldAspect {Before(get(* com.example.demo.model.User.name))public void beforeFieldAccess(JoinPoint joinPoint) {// 拦截 User 类中的 name 字段的 getter 方法}}在上面的示例中使用 get 切点匹配器匹配 User 类中的 name 字段的 getter 方法实现对字段级别的拦截。
构造方法级别
要拦截构造方法级别的切面可以使用 AspectJ 提供的 initialization 切点匹配器例如
Aspect
public class ConstructorAspect {Before(execution(com.example.demo.model.User.new()))public void beforeConstructorExecution(JoinPoint joinPoint) {// 拦截 User 类的构造方法}}在上面的示例中使用 execution 切点匹配器匹配 User 类的构造方法实现对构造方法级别的拦截。
类级别
要拦截类级别的切面可以使用 AspectJ 提供的 type 切点匹配器例如
Aspect
public class ClassAspect {Before(execution(* com.example.demo.service.*.*(..)) type(service))public void beforeServiceMethodExecution(JoinPoint joinPoint) {// 拦截 com.example.demo.service 包下的所有方法并且方法所属的类必须被 Service 注解标注}}在上面的示例中使用 execution 切点匹配器匹配 com.example.demo.service 包下的所有方法并且方法所属的类必须被 Service 注解标注实现对类级别的拦截。
需要注意的是AspectJ 的切面匹配器比 Spring AOP 更加灵活可以匹配更多的切点。但是AspectJ 的使用需要在编译期间进行织入因此相对来说也更加复杂和耗费资源。在实际使用中需要根据实际需求选择使用 Spring AOP 还是 AspectJ。 使用 AspectJ, 要引入什么jar包 Spring Boot 默认使用 Spring AOP如果要使用 AspectJ需要手动引入 AspectJ 相关的依赖。
可以在 pom.xml 文件中添加以下依赖
dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.7/version
/dependency
dependencygroupIdorg.aspectj/groupIdartifactIdaspectjrt/artifactIdversion1.9.7/version
/dependency其中aspectjweaver 依赖是必须的它包含了 AspectJ 的运行时环境aspectjrt 依赖是可选的它包含了 AspectJ 的运行时库如果使用了 AspectJ 的注解建议添加该依赖。
在添加了依赖后可以在启动类上添加 EnableAspectJAutoProxy 注解开启 AspectJ 支持或者在切面类上使用 Aspect 注解定义切面类。
Spring AOP | 易用但仅支持方法 Spring AOP 只支持方法级别的切面 Spring AOP 只支持方法级别的切面指的是Spring AOP 只能拦截方法的执行而不能拦截其他级别的切面例如字段级别、构造方法级别、类级别等。
这是因为 Spring AOP 的实现方式是基于 JDK 动态代理或 CGLIB 字节码生成技术的而 JDK 动态代理和 CGLIB 都是基于方法级别的。在使用 JDK 动态代理时代理对象必须实现一个或多个接口而接口是方法集合的抽象因此只能对接口中定义的方法进行拦截在使用 CGLIB 字节码生成技术时会生成一个新的类作为代理类该类是原始类的子类因此只能拦截原始类中的方法无法拦截字段、构造方法等。
不过Spring AOP 还提供了其他的一些拦截点例如 Bean 生命周期事件可以在 Bean 初始化前后、销毁前后等事件中执行通知。 AspectJ 注解可以使用 AspectJ 注解来实现更为灵活的切面拦截支持字段级别、构造方法级别、类级别等切入点。
需要注意的是使用 AspectJ 注解时需要添加相应的 AspectJ 依赖并配置 AspectJ 编译器以支持注解的解析和织入。
aop 原理
通过 EnableAspectJAutoProxy 将aop的功能通过bean后置处理器, 关联到我们的IOC容器中 EnableAspectJAutoProxy 的目的是为了导入 AnnotationAwareAspectJAutoProxyCreator AnnotationAwareAspectJAutoProxyCreator 又是bean后置处理器, 这不就挂钩上了吗
史上最完整的AOP底层原理_哔哩哔哩_bilibili
一文吃透spring aop底层原理_spring aop的底层原理_吴法刚的博客-CSDN博客
那么AOP具体是如何在我体内运行的呢在我启动时会创建IOC容器, 同时将我体内的bean进行三个连续的动作, 构造 填充 属性初始化
AOP功能就是通过我体内一个专门处理AOP的bean后置处理器 DefaultAdvisorAutoProxyCreator 进行方法增强的,
可以算作IOC容器的附加功能, 所有的后置处理器都在bean构造完, 并且填充了属性之后执行 填充了属性之后执行 在每一个bean初始化之后都会调用这个后置处理器的postProcessorAfterInitialization 方法, 在这个方法里为需要使用AOP的bean创建代理对象。 先通过getAdvicesAndAdvisorsForBean方法, 获取所有的增强Advice, 同时判断当前bean是否满足我们配置的切面条件 如果满足条件的话, 就会为这个bean构造代理对象来实现AOP 为了更统一更方便的构造代理对象, 我会先搭建一个专门用来构造生产代理对象的工厂, proxyFactory, 我会告诉这个工厂具体选择哪种方式进行代理, 分别是cglib和jdkProxy。
通过添加EnableAspectJAutoProxy注解, 并且将其中proxyTargetClass配置改为 true 强制使用cglib。 当然啦在spring boot中默认就是使用cglib, 不过只有这个配置为false, 同时该类实现了任意接口才会使用jdkProxy, 否则还是会使用cglib方式。 ProxyFactory知道使用哪种方式之后, 就会构造jdkDynamicAopProxy或者cglibAopProxy, 然后就可以通过他们的getProxy方法获得真正的代理对象。 jdkDynamicAopProxy 先说相对简单, 而且即将被我无情放弃的jdkDynamicAopProxy, 在getProxy中会构造一个实现同样bean接口的代理对象, 将真实bean作为代理, 对象中的一个成员变量。 在调用bean方法的时候就会执行代理对象中的 invoke 方法 这个 invoke 方法只有两步, 我会通过之前提到的execution表达式, 获取所有与该方法匹配的所有增强方法, 并将它们组成调用链同时进行排序 开始按顺序执行这些调用链, 这里的调用方式就是经典的责任链模式, 在调用中间会插入bean 执行bean真实的方法 cglibAopProxy 最为常用的cglibAopProxy, 同样会在getProxy方法中构造代理对象
用增强器 Enhancer 来设置代理基本信息以及增强方法的调用链 接着执行 Enhancer create方法来生成代理对象
和jdkDynamicAopProxy不同的是cglib是基于jdk rt jar包中的asm来生成一组新的class文件, 然后实例化它的对象, 所以对于没有实现接口的bean也可以生成代理对象
在调用bean方法的时候, 会先执行代理对象的intercept方法, 与jdkProxy一样, 也会通过责任链来执行所有的方法增强。