Spring aop之针对注解

news2025/2/25 6:04:41

前言

  接触过Spring的都知道,aop是其中重要的特性之一。笔者在开发做项目中,aop更多地是要和注解搭配:在某些方法上加上自定义注解,然后要对这些方法进行增强(很少用execution指定,哪些包下的哪些方法要增强)。那这时就要引出@annotation、@target、@within了。我们一一讲解。

@annotation

  方法上是否有指定注解;子类调用不重写的方法会被aop拦截,调用重写的方法看是否加了指定注解。


  首先引入依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.7.4</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.7.4</version>
    <scope>test</scope>
</dependency>

  自定义一个注解:

import java.lang.annotation.Target;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Outer {

    int limit() default 0;

}

  目标类:

import org.springframework.stereotype.Component;

@Component
public class Target {

    @Outer(limit = 8)
    public void invoke() {
        System.out.println("执行Target的方法");
    }
    
}
@Component
public class SonTarget extends Target {
		
}

  切面类:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Component
@Aspect
public class MyAspect {

    @Around("@annotation(com.gs.spring_boot_demo.aop.Outer)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Method method = ((MethodSignature)point.getSignature())
                        .getMethod();
        Outer outer = method.getAnnotation(Outer.class);

        System.out.println("aop前置:" + outer.limit());
        return point.proceed();
    }

}

  编写测试类:

import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.jupiter.api.Test;

@SpringBootTest
public class AopTest {

    @Resource
    private Target target;

    @Autowired
    private SonTarget sonTarget;

    @Test
    public void aop() {
        target.invoke();
        System.out.println("---");
        sonTarget.invoke();
    }
    
}

  运行aop方法,打印结果:

在这里插入图片描述


  把子类SonTarget修改一下,

import org.springframework.stereotype.Component;

@Component
public class SonTarget extends Target {
	
    public void invoke() {
        System.out.println("子类执行Target的方法");
    }

}

  再次运行测试类,这时子类的invoke()方法不会被拦截了:

在这里插入图片描述

  当然,如果SonTarget的invoke()方法上加上@Outer,那就能被aop拦截了。


@target

  调用方法的对象,所属的类上是否有指定注解;注解被@Inherited修饰,子类调用会生效;无@Inherited,看子类上有无该注解。


  自定义注解不动,目标类修改为:
import org.springframework.stereotype.Component;

@Component
@Outer(limit = 8)
public class Target {
	
    public void invoke() {
        System.out.println("执行Target的方法");
    }

}
import org.springframework.stereotype.Component;

@Component
public class SonTarget extends Target {
	
    public void invoke() {
        System.out.println("子类执行Target的方法");
    }

}

  切面类修改为:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Component
@Aspect
public class MyAspect {

    /**
     * 要注意一下,@target很硬霸:所有的bean都会被动态代理(不管类上有没有加自定
     * 义注解),所以要约束为:本项目下的包下
     * 不然测试用例运行时会报错:依赖中有些类是final的,被动态代理会报错
     */
	@Around("@target(com.gs.spring_boot_demo.aop.Outer) && 
	        within(com.gs.spring_boot_demo..*)")
	public void around(ProceedingJoinPoint point) throws Throwable {
	    Method method = ((MethodSignature)point.getSignature())
	                    .getMethod();
	    Outer outer = method.getDeclaringClass().getAnnotation(
	                  Outer.class);
	
	    System.out.println("aop前置:" + outer.limit());
	    point.proceed();
	}

}

  测试类不动,运行:

在这里插入图片描述

  SonTarget的invoke()没有被拦截,想要被拦截,就在SonTarget类上添加@Outer;或者自定义注解上增加@Inherited(表明父类加上该注解后,子类能够继承):

import java.lang.annotation.Target;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Outer {

    int limit() default 0;

}

@within

  方法所属的类上,是否有指定注解;注解没有被@Inherited修饰,子类调用不重写的方法会被拦截,调用重写的方法看子类上是否有注解;注解被@Inherited修饰,子类调用方法都会被拦截,不管是否重写

  自定义注解改一下,就把修饰它的@Inherited去掉;
  目标类:

import org.springframework.stereotype.Component;

@Component
@Outer(limit = 8)
public class Target {
	
    public void invoke() {
        System.out.println("执行Target的方法");
    }

}
import org.springframework.stereotype.Component;

@Component
public class SonTarget extends Target {
	
}

  切面类修改为:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Component
@Aspect
public class MyAspect {
	
    @Around("@within(com.gs.spring_boot_demo.aop.Outer)")
    public void around(ProceedingJoinPoint point) throws Throwable {
        Method method = ((MethodSignature)point.getSignature())
                        .getMethod();
        Outer outer = method.getDeclaringClass().getAnnotation(
                      Outer.class);

        System.out.println("aop前置:" + outer.limit());
        point.proceed();
    }

}

  测试类不动,运行:

在这里插入图片描述

  子类的方法能被拦截;我们把子类的方法重写一下:

import org.springframework.stereotype.Component;

@Component
public class SonTarget extends Target {
	
    public void invoke() {
        System.out.println("子类执行Target的方法");
    }

}

  再次运行测试类,打印出结果:

在这里插入图片描述

  子类的方法没有被拦截,想要被拦截,SonTarget类上加上@Outer。

  我们再试一下自定义注解被@Inherited修饰的情况。@Outer注解加上@Inherited,然后Target不动,SonTarget也不动(重写了invoke()方法,类上也没有@Outer),运行测试类:

在这里插入图片描述

  SonTaget改一下,不重写invoke()方法,运行测试类:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/361896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日一题——L1-069 胎压监测(15)

L1-069 胎压监测 分数 15 小轿车中有一个系统随时监测四个车轮的胎压&#xff0c;如果四轮胎压不是很平衡&#xff0c;则可能对行车造成严重的影响。 让我们把四个车轮 —— 左前轮、右前轮、右后轮、左后轮 —— 顺次编号为 1、2、3、4。本题就请你编写一个监测程序&#…

Windows 10/11如何恢复已删除的照片?

如果你想在Windows 11或Windows 10上恢复已删除的照片&#xff0c;你可以参考这篇文章&#xff0c;使用2种方法轻松恢复Windows上永久删除的照片。 可以恢复电脑上已删除的照片吗&#xff1f; 随着科技的发展&#xff0c;越来越多的用户习惯于在电子设备上存储照片。如果这些…

实时渲染为什么快,能不能局域网部署点量云

提到渲染很多有相关从业经验的人员可能会想起&#xff0c;自己曾经在电脑上渲染一个模型半天或者更长的 时间才能完成的经历。尤其是在项目比较着急的时候&#xff0c;这种煎熬更是难受。但现在随着实时渲染和云渲染行业的发展&#xff0c;通过很多方式可以提升渲染的时间和效率…

管理数据就这样轻松:TablePlus 5.3.1Crack

数据库管理变得简单 适用于关系数据库的现代、原生且友好的 GUI 工具&#xff1a;MySQL、PostgreSQL、SQLite 等 支持一整套关系数据库&#xff08;和一些 NoSQL&#xff09; 数据库MySQL红移数据库服务器SQLite数据库雷迪斯卡桑德拉蟑螂数据库数据库垂直 我们的客户来自世界上…

数据结构(四):树、二叉树、二叉搜索树

数据结构&#xff08;四&#xff09;一、树1.树结构2.树的常用术语二、二叉树1.什么是二叉树2.二叉树的数据存储&#xff08;1&#xff09;使用数组存储&#xff08;2&#xff09;使用链表存储三、二叉搜索树1.这是什么东西2.封装二叉搜索树&#xff1a;结构搭建3. insert插入节…

分析| 2023年移动开发平台的发展空间

春节过后返工已经过月&#xff0c;许多移动开发领域的企业都在忙着做技术调研与选型。在此之前&#xff0c;不如先回顾一下2022年的市场趋势&#xff0c;再结合好的移动开发平台的标准&#xff0c;从中窥见2023年的发展前景。 Gartner十大战略技术趋势 全球权威咨询机构Gartne…

ChatGPT写程序如何?

前言ChatGPT最近挺火的&#xff0c;据说还能写程序&#xff0c;感到有些惊讶。于是在使用ChatGPT有一周左右后&#xff0c;分享一下用它写程序的效果如何。1、对于矩阵&#xff0c;把减法操作转换加法&#xff1f;感觉不错的&#xff0c;能清晰介绍原理&#xff0c;然后写示例程…

运动健身用什么耳机好、最健身使用的耳机推荐清单

健身锻炼已经趋向于“国民运动”了&#xff0c;大家都喜欢一边听歌一边挥洒汗水&#xff0c;但是运动时戴的耳机也是有学问在里边的&#xff0c;需要满足佩戴牢固、防水防汗的基本需求&#xff0c;并且&#xff0c;根据每个人运动偏好的不同选择倾向也不同&#xff0c;在这里我…

HDLC简介及相应hdlc实训

HDLC简介 HDLC 协议 高级数据链路控制&#xff08;HDLC&#xff0c;High-level Data Link Control&#xff09;是一种面向比特的链路层协议&#xff0c; 其最大特点是对任何一种比特流&#xff0c;均可以实现透明的传输。HDLC协议具有以下优点。 透明传输&#xff1a;HDLC不…

动漫插画培训班有哪些

动漫培训班有哪些&#xff0c;今天给大家带来的是国内专业的动漫培训机构排名&#xff0c;这5个动漫培训机构&#xff0c;相信你一定都知道&#xff0c;快来看看吧&#xff01; 一&#xff1a;动漫培训机构排名 1、轻微课 轻微课是国内人气很高的板绘学习平台&#xff0c;主打课…

经典文献阅读之--VoxelMap(体素激光里程计)

0. 简介 作为激光里程计&#xff0c;常用的方法一般是特征点法或者体素法&#xff0c;最近Mars实验室发表了一篇文章《Efficient and Probabilistic Adaptive Voxel Mapping for Accurate Online LiDAR Odometry》&#xff0c;同时还开源了代码在Github上。文中为雷达里程计提…

基于机器学习的异常检测与分析技术

传统的运维方式在监控、问题发现、告警以及故障处理等各个环节均存在明显不足&#xff0c;需要大量依赖人的经验&#xff0c;在数据采集、异常诊断分析、故障处理的效率等方面有待提高。 本关键技术面对传统运维故障处理效率低、问题定位不准确、人力成本高三大痛点&#xff0…

AXI实战(二)-跟着产品手册设计AXI-Lite外设(AXI-Lite转串口实现)

AXI实战(二)-跟着产品手册设计AXI-Lite 设(AXI-Lite转串口实现) 看完在本文后,你将可能拥有: 一个AXI_Lite转串口的从端(Slave)设计使用SV仿真AXI-Lite总线的完整体验实现如何在读通道中实现"等待"小何的AXI实战系列开更了,以下是初定的大纲安排: 欢迎感兴趣的…

【机器学习】为什么训练集用fit_transform而测试集只用transform?

文章目录一、解释二、归一化&#xff08;Normalization&#xff09;三、为什么只对训练集做fit_transform&#xff0c;对测试集只做transform&#xff1f;一、解释 fit(): Method calculates the parameters μ and σ and saves them as internal objects.解释&#xff1a;简…

使用vue3+vantUi3.x版本,van-list列表组件,控制台报错

van-list报错过程 在vue3.0vantUi3.x版本中&#xff0c;使用List列表组件时&#xff0c;代码就是官方给的demo&#xff1a; <van-listv-model:loading"loading":finished"finished"finished-text"没有更多了"load"onLoad" >&l…

甘肃西部河谷科技有限公司官网上线 | LTD技术行业案例分享

甘肃西部河谷信息科技有限公司成立于2018年&#xff0c;是一家专业的IT技术推广与服务公司。主营业务有智慧城市、智慧校园、智慧农业、信息技术设备软件研发、集成销售&#xff1b;安防设备、网络工程、市场营销策划、电子商务信息、技术咨询服务等。公司立足高端IT技术服务&a…

CODESYS开发教程11-库管理器

今天继续我们的小白教程&#xff0c;老鸟就不要在这浪费时间了&#x1f60a;。 前面一期我们介绍了CODESYS的文件读写函数库SysFile。大家可能发现了&#xff0c;在CODESYS的开发中实际上是离不开各种库的使用&#xff0c;其中包括系统库、第三方库以及用户自己开发的库。实际…

2023年测试人跳槽新功略,涨薪10K+

软件测试是如何实现涨薪的呢&#xff1f;很多人眼中的软件测试岗位可能是简单的&#xff0c;技术含量不是那么高&#xff0c;就是看看需求、看业务、设计文档、然后点一点功能是否实现&#xff0c;再稍微深入一点就是测试下安装部署时会不会出现兼容性问题&#xff0c;以及易用…

【Spring Cloud Alibaba】002-Spring Cloud Alibaba

【Spring Cloud Alibaba】002-Spring Cloud Alibaba 文章目录【Spring Cloud Alibaba】002-Spring Cloud Alibaba一、Spring Cloud Alibaba 介绍1、介绍2、 Spring Cloud Alibaba 提供的功能模块二、分布式项目搭建1、项目搭建2、访问测试3、结论三、Spring Cloud Alibaba 环境…

一文带你精通分布式锁

在单机环境下&#xff0c;由于使用环境简单和通信可靠&#xff0c;锁的可见性和原子性很容易可以保证&#xff0c;可以简单和可靠地实现锁功能。到了分布式的环境下&#xff0c;由于公共资源和使用方之间的分离&#xff0c;以及使用方和使用方之间的分离&#xff0c;相互之间的…