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

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

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

在这里插入图片描述

一、切入点表达式和方法

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

在这里插入图片描述

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

二、练习

2.1、只有 login 方法会被切中

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

测试:

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

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

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

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

测试:

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

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

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

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

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

测试:

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

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

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

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

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

测试:

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

三、问题

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

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

四、精确切入

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

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

  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)"

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

测试:

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

5.3、within()

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

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

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

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

测试:

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

5.3、@annotation()

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

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

MyAffair

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

然后在 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;
    }
}

表达式

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

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

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

测试:

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

六、切入点函数逻辑运算

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

6.1、and与

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

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

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

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

这根本就不存在

6.1、or或

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

login 或 register 都可以

七、写在最后

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

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

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

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王子周棋洛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值