# 《Spring核心技术》第27章:深度解析@DeclareParents注解
作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码地址:https://github.com/binghe001/spring-annotation-book/tree/master/spring-annotation-chapter-27 (opens new window)
沉淀,成长,突破,帮助他人,成就自我。
大家好,我是冰河~~
本章难度:★★★★☆
本章重点:进一步学习并掌握@DeclareParents注解加入新方法的案例和流程,从源码级别彻底掌握@DeclareParents注解在Spring底层的执行流程。
本章目录如下所示:
- 学习指引
- 注解说明
- 注解源码
- 使用场景
- 使用案例
- 原有功能的实现
- 基于手写逻辑实现校验
- 基于前置通知实现校验
- 源码时序图
- 源码解析
- 总结
- 思考
- VIP服务
# 一、学习指引
在Spring AOP中,你了解过@DeclareParents注解吗?
很多小伙伴用了很多年的Spring,但是对@DeclareParents注解了解的非常少。那我说一个场景,你多多少少会有点体会:比如你接手了一个基于Spring开发的项目,这个项目的业务比较复杂,代码也比较乱。你想在某个类中新增一个方法来校验某些逻辑,但是这个类不知道在多少地方被使用,改动一个地方有点牵一发动全身的感觉,没错,代码就是犹如“屎山”一样,根本就没有办法在原来的类上新增方法。此时,如果你了解Spring的@DeclareParents注解,就能够轻松应对这种情况。
# 二、注解说明
关于@DeclareParents注解的一点点说明~~
在实际工作过程中,难免会遇到突然接手其他人写的项目,或者接手的某个项目已经经历“几代人”的手,妥妥的“屎山”,改代码牵一发动全身,此时就可以使用到@DeclareParents注解给被增强的类提供一些新的方法。
# 2.1 注解源码
@DeclareParents注解可以为被增强的类实现新的接口,并且可以添加新的方法。@DeclareParents注解的源码详见:org.aspectj.lang.annotation.DeclareParents。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DeclareParents {
String value();
Class defaultImpl() default DeclareParents.class;
}
2
3
4
5
6
从源码可以看出,@DeclareParents注解可以标注到字段上,并且提供了一个String类型的value属性和一个Class类型的defaultImpl属性。
- value:指定目标类型的表达式,如果在全类名的后面添加 + ,则表示的是当前类及其子类。
- defaultImpl:指定方法或者字段的默认实现类。
# 2.2 使用场景
除了前面说的接手“屎山”项目,改代码牵一发动全身的场景外。还有一个场景就是:在正常开发业务项目的过程中,当项目已经开发到某个阶段时,此时突然发现某个类少一个功能,想在某个类中添加新的方法。但是这个类比较复杂,同样会涉及到牵一发动全身的感觉,改动起来比较麻烦。此时,也可以使用@DeclareParents注解,在不改动原有代码的前提下实现新增方法的功能。
# 三、使用案例
一起实现@DeclareParents注解的案例,怎么样?
在案例的实现中,模拟一个原来就基于接口实现好的保存或者更新某个对象的功能,此时,需要在不改动原有代码的基础上在保存或者更新对象之前,先校验下待保存或者更新的对象中属性值的合法性,如果合法,则正常执行保存操作,如果不合法,则抛出异常。
# 3.1 原有功能的实现
本节,先来完成原有的模拟保存或者更新对象的功能,具体的实现步骤如下所示。
(1)新增DeclareParentsBean类
DeclareParentsBean类的源码详见:spring-annotation-chapter-27工程下的io.binghe.spring.annotation.chapter27.bean.DeclareParentsBean。
public class DeclareParentsBean {
public static final String NAME = "binghe";
private String name;
public DeclareParentsBean() {
}
public DeclareParentsBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "DeclareParentsBean{" +
"name='" + name + '\'' +
'}';
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
可以看到,DeclareParentsBean类就是一个普通的Java类,在DeclareParentsBean类中提供了一个name属性。
# 查看完整文章
加入冰河技术 (opens new window)知识星球,解锁完整技术文章与完整代码