Spring 从入门到精通 (十四) 切入点详解

举报
周棋洛 发表于 2022/07/24 22:37:25 2022/07/24
【摘要】 关键词:Spring | 切入点 | 详解 本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨ 目录 一、切入点表...

关键词:Spring | 切入点 | 详解

本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨

在这里插入图片描述

一、切入点表达式和方法

切入点表达式的语法和方法的结构是一一对应的

在这里插入图片描述

从上图不难看出,为什么所有方法的切入点表达式要写成 * *(..)

二、练习

2.1、只有 login 方法会被切中

expression="execution(* login(..))"

  
 
  • 1

测试:

可以看到 login 方法被代理了,而 register 方法没有

----开启事务----
UserServiceImpl login + DAO
----提交事务----
UserServiceImpl register + DAO

  
 
  • 1
  • 2
  • 3
  • 4

2.2、两个参数都是 String 类型的方法才会被切中

expression="execution(* *(String,String))"

  
 
  • 1

测试:

因为 login 方法的两个参数都是 String 类型,满足要求,被切中代理了,而 register 方法的参数是一个 User 对象,不满足要求

----开启事务----
UserServiceImpl login + DAO
----提交事务----
UserServiceImpl register + DAO

  
 
  • 1
  • 2
  • 3
  • 4

2.3、参数类型是User类型的方法会被切中

expression="execution(* *(com.liu.entity.User))"

  
 
  • 1

注意: User参数不是 java.lang 包下的,因此必须写入类全限定名

测试:

这次应该是 register 被切中了,因为它的参数类型是 User

UserServiceImpl login + DAO
----开启事务----
UserServiceImpl register + DAO
----提交事务----

  
 
  • 1
  • 2
  • 3
  • 4

2.4、连用…,中间使用逗号分隔

expression="execution(* *(String,..))"

  
 
  • 1

这个意思就是修饰符返回值任意,方法名字任意,第一个参数必须是 String 类型,后面的参数有几个都可以,类型是什么都可以,只要满足上面的条件就会被切中,分析满足条件的只有 login 方法了

测试:

----开启事务----
UserServiceImpl login + DAO
----提交事务----
UserServiceImpl register + DAO

  
 
  • 1
  • 2
  • 3
  • 4

三、问题

我们发现其实这个表达式很简单,很实用,但是现在的写法有个很致命的问题,切的范围不准确,只是在方法级别,假如不同的包,我需要切中某包下的这个方法,应该怎么做呢?

下面就继续深入学习切入点表达式,加油!

四、精确切入

其实很简单,上面的方法其实是一种简写,我们想要切中某个包下的类中的方法,无非就从包开始限定就可以了

修饰符 返回值     包.类.方法(参数)

  1. execution(* com.liu.service.*.*(..))
    包:com.liu.service
    类:任意类
    方法:任意方法
    参数:任意参数
    返回值:任意返回值类型

  2. execution(String com.liu.service.*ServiceImpl.*(..))
    包:com.liu.service
    类:以ServiceImpl结尾的类
    方法:任意方法名
    参数:任意
    返回值:必须是String类型相关方法

  3. execution(String com.liu.service.*Service*.*(String))
    包:com.liu.service
    类:类名中包含Service关键字的类
    方法:任意
    参数:参数只有一个,类型必须是String类型
    返回值:返回值必须是String

  4. execution(* com.liu.service..*.*(..))
    包:com.liu.service以及下面的所有子包
    类:任意类
    方法:任意方法
    参数:任意参数
    返回值:任意类型

  5. execution(* com.liu.service.*ServiceImpl.*(..))
    包:com.liu.service
    类:以ServiceImpl结尾的类
    方法:任意方法名
    参数:任意
    返回值:任意类型

  6. execution(* *(..)) 避免使用
    包:项目中所有包
    类:项目中所有类
    方法:所有方法
    参数:所有参数
    返回值:任意参数

五、切入点函数

用于执行切入点表达式

Spring提供了很多切入点函数,用于不同的场景,可以一定程度上简化一些配置

5.1、execution()

前面已经学过了,最重要的一个,其他函数能实现的它都能实现,不好的地方就是书写必须很全。

5.2、args()

关注点:主要用于函数(方法)参数的匹配

举例: 必须是两个String类型参数的方法,其他的包啊类啊我不关心,这时就可以使用

expression="args(String,String)"

  
 
  • 1

不出意外,应该是 login 方法被切中了

测试:

----开启事务----
UserServiceImpl login + DAO
----提交事务----
UserServiceImpl register + DAO

  
 
  • 1
  • 2
  • 3
  • 4

5.3、within()

关注点:主要用于关注类,包的切入点,不关心方法修饰符,返回值以及参数

举例: com.liu.Service.UserServiceImpl 包下的所有方法都被切中

expression="within(com.liu.service.UserServiceImpl)"

  
 
  • 1

不出意外,UserServiceImpl 包下的所有方法,也就是 login 和 register 方法被切中了

测试:

----开启事务----
UserServiceImpl login + DAO
----提交事务----
----开启事务----
UserServiceImpl register + DAO
----提交事务----

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5.3、@annotation()

自定义注解并使用时,可以使用@annotation()去查找哪些类或方法使用了这个注解,并添加额外功能

首先自定义注解 MyAffair,意思是我们自定义的事务注解

MyAffair

// 注解作用目标 在方法上使用
@Target(ElementType.METHOD)
// 注解执行时机 运行时才有用
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAffair {    
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后在 UserServiceImpl 类方法上使用此注解

public class UserServiceImpl implements UserService{
    @Override
    @MyAffair
    public void register(User user) {
        System.out.println("UserServiceImpl register + DAO");
    }

    @Override
    @MyAffair
    public boolean login(String name, String pwd1) {
        System.out.println("UserServiceImpl login + DAO");
        return true;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

表达式

注意:此时使用的切入点函数为@annotation,表达式写的就是我们自定义注解的全包名。

expression="@annotation(com.liu.MyAffair)"

  
 
  • 1

此时,启动程序,切入点表达式发现你使用自定义注解的方式,就去查找添加了自定义注解的方法,并全部添加额外功能

测试:

----开启事务----
UserServiceImpl login + DAO
----提交事务----
----开启事务----
UserServiceImpl register + DAO
----提交事务----

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

六、切入点函数逻辑运算

整合多个切入点函数,从而完成更为复杂的需求

6.1、and与

假设要切中 login 方法,同时方法参数为两个字符串

-- 之前
execution(* login(String,String))
-- 之后
execution(* login(..)) and args(String,String)

  
 
  • 1
  • 2
  • 3
  • 4

注意: 与操作不能用于同种类型的切入点函数,比如

execution(* login(..)) and execution(* register(..))

  
 
  • 1

这根本就不存在

6.1、or或

execution(* login(..)) or execution(* register(..))

  
 
  • 1

login 或 register 都可以

七、写在最后

座右铭:不要在乎别人如何看你,要在乎你自己如何看未来,看梦想,看世界…!

一起学习的可以私信博主或添加博主微信哦。

专栏:订阅专栏 ✅
关注:关注博主 🆙

文章来源: blog.csdn.net,作者:王子周棋洛,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/m0_53321320/article/details/125947980

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。