Spring 源码第四弹!深入理解 BeanDefinition

本文详细解读了Java面试中可能出现的BeanDefinition接口及其实现类,如RootBeanDefinition和GenericBeanDefinition,同时介绍了Spring框架的配置原理。此外,还分享了算法复习策略,以及Redis、MySQL、Kafka和网络等相关知识要点。
摘要由CSDN通过智能技术生成

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

String getInitMethodName();

void setDestroyMethodName(@Nullable String destroyMethodName);

@Nullable

String getDestroyMethodName();

void setRole(int role);

int getRole();

void setDescription(@Nullable String description);

@Nullable

String getDescription();

ResolvableType getResolvableType();

boolean isSingleton();

boolean isPrototype();

boolean isAbstract();

@Nullable

String getResourceDescription();

@Nullable

BeanDefinition getOriginatingBeanDefinition();

}

BeanDefinition 中的方法虽然多,但是结合我们平时在 XML 中的配置,这些方法其实都很好理解:

  1. 首先一开始定义了两个变量用来描述 Bean 是不是单例的,后面的 setScope/getScope 方法可以用来修改/获取 scope 属性。

  2. ROLE_xxx 用来描述一个 Bean 的角色,ROLE_APPLICATION 表示这个 Bean 是用户自己定义的 Bean;ROLE_SUPPORT 表示这个 Bean 是某些复杂配置的支撑部分;ROLE_INFRASTRUCTURE 表示这是一个 Spring 内部的 Bean,通过 setRole/getRole 可以修改。

  3. setParentName/getParentName 用来配置 parent 的名称,这块可能有的小伙伴使用较少,这个对应着 XML 中的 <bean parent=""> 配置。

  4. setBeanClassName/getBeanClassName 这个就是配置 Bean 的 Class 全路径,对应 XML 中的 <bean class=""> 配置。

  5. setLazyInit/isLazyInit 配置/获取 Bean 是否懒加载,这个对应了 XML 中的 <bean lazy-init=""> 配置。

  6. setDependsOn/getDependsOn 配置/获取 Bean 的依赖对象,这个对应了 XML 中的 <bean depends-on=""> 配置。

  7. setAutowireCandidate/isAutowireCandidate 配置/获取 Bean 是否是自动装配,对应了 XML 中的 <bean autowire-candidate=""> 配置。

  8. setPrimary/isPrimary 配置/获取当前 Bean 是否为首选的 Bean,对应了 XML 中的 <bean primary=""> 配置。

  9. setFactoryBeanName/getFactoryBeanName 配置/获取 FactoryBean 的名字,对应了 XML 中的 <bean factory-bean=""> 配置,factory-bean 松哥在之前的入门视频中讲过,小伙伴们可以参考这里:https://www.bilibili.com/video/BV1Wv41167TU

  10. setFactoryMethodName/getFactoryMethodName 和上一条成对出现的,对应了 XML 中的 <bean factory-method=""> 配置,不再赘述。

  11. getConstructorArgumentValues 返回该 Bean 构造方法的参数值。

  12. hasConstructorArgumentValues 判断上一条是否是空对象。

  13. getPropertyValues 这个是获取普通属性的集合。

  14. hasPropertyValues 判断上一条是否为空对象。

  15. setInitMethodName/setDestroyMethodName 配置 Bean 的初始化方法、销毁方法。

  16. setDescription/getDescription 配置/返回 Bean 的描述。

  17. isSingleton Bean 是否为单例。

  18. isPrototype Bean 是否为原型。

  19. isAbstract Bean 是否抽象。

  20. getResourceDescription 返回定义 Bean 的资源描述。

  21. getOriginatingBeanDefinition 如果当前 BeanDefinition 是一个代理对象,那么该方法可以用来返回原始的 BeanDefinition 。

这个就是 BeanDefinition 的定义以及它里边方法的含义。

2.BeanDefinition 实现类


上面只是 BeanDefinition 接口的定义,BeanDefinition 还拥有诸多实现类,我们也来大致了解下。

先来看一张继承关系图:

这么多实现类看着有点眼花缭乱,不过搞清楚了每一个接口和类的作用,再看就很容易了。

2.1 AbstractBeanDefinition

AbstractBeanDefinition 是一个抽象类,它根据 BeanDefinition 中定义的接口提供了相应的属性,并实现了 BeanDefinition 中定义的一部分方法。BeanDefinition 中原本只是定义了一系列的 get/set 方法,并没有提供对应的属性,在 AbstractBeanDefinition 中将所有的属性定义出来了。

后面其他的实现类也基本上都是在 AbstractBeanDefinition 的基础上完成的。

2.2 RootBeanDefinition

这是一个比较常用的实现类,对应了一般的元素标签。

2.3 ChildBeanDefinition

可以让子 BeanDefinition 定义拥有从父 BeanDefinition 那里继承配置的能力。

2.4 GenericBeanDefinition

GenericBeanDefinition 是从 Spring2.5 以后新加入的 BeanDefinition 实现类。GenericBeanDefinition 可以动态设置父 Bean,同时兼具 RootBeanDefinition 和 ChildBeanDefinition 的功能。

2.5 AnnotatedBeanDefinition

表示注解类型 BeanDefinition,拥有获取注解元数据和方法元数据的能力。

2.6 AnnotatedGenericBeanDefinition

使用了 @Configuration 注解标记配置类会解析为 AnnotatedGenericBeanDefinition。

3.实践


理论讲了这么多,接下来我们通过几行代码来实践下,验证一下我们前面所说的对不对。

首先项目中添加 spring-context 依赖,如下:

org.springframework

spring-context

5.2.6.RELEASE

然后我们来创建一个 User 类,如下:

public class User {

private String username;

private String address;

@Override

public String toString() {

return “User{” +

“username='” + username + ‘’’ +

“, address='” + address + ‘’’ +

‘}’;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

}

接下来我们先来验证 RootBeanDefinition。我们自己纯手工定义一个 RootBeanDefinition,并且将之注册到 Spring 容器中去。

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

MutablePropertyValues pvs = new MutablePropertyValues();

pvs.add(“username”, “javaboy”);

pvs.add(“address”, “www.javaboy.org”);

RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class, null, pvs);

ctx.registerBeanDefinition(“user”,rootBeanDefinition);

ctx.refresh();

User bean = ctx.getBean(User.class);

System.out.println(bean);

MutablePropertyValues 是定义对象中的一个一个属性,构造 RootBeanDefinition 的时候,我们传入了类名称和属性集合,最终把 rootBeanDefinition 注册到容器中去。剩下的事情由容器完成,然后我们就可以从容器中获取到 User 对象了。

最终输出结果如下:

User{username=‘javaboy’, address=‘www.javaboy.org’}

看了这个例子,小伙伴们应该能够大致明白,我们在 XML 中定义的各种属性,就是先被解析到 BeanDefinition 中,然后再注册到 Spring 容器中去,最后拿到我们需要的 Bean。

ChildBeanDefinition 具有从父 Bean 继承数据的能力,我们来看下这个怎么用。

首先新建一个 Person 类,Person 类在 User 类的基础上增加一个 nickname 属性,这样 Person 就可以继承到 User 的 username 和 address 两个属性的值了:

public class Person {

private String username;

private String address;

private String nickname;

@Override

public String toString() {

return “Person{” +

“username='” + username + ‘’’ +

“, address='” + address + ‘’’ +

“, nickname='” + nickname + ‘’’ +

‘}’;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

public String getNickname() {

return nickname;

}

public void setNickname(String nickname) {

this.nickname = nickname;

}

}

接下来自定义 ChildBeanDefinition:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

MutablePropertyValues pvs = new MutablePropertyValues();

pvs.add(“username”, “javaboy”);

pvs.add(“address”, “www.javaboy.org”);

RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class, null, pvs);

ctx.registerBeanDefinition(“user”,rootBeanDefinition);

ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition(“user”);

childBeanDefinition.setBeanClass(Person.class);

childBeanDefinition.getPropertyValues().add(“nickname”, “江南一点雨”);

ctx.registerBeanDefinition(“person”, childBeanDefinition);

ctx.refresh();

User user = ctx.getBean(User.class);

Person person = ctx.getBean(Person.class);

System.out.println("user = " + user);

System.out.println("person = " + person);

首先定义 RootBeanDefinition 并注册到 Spring 容器中,然后再定义 ChildBeanDefinition,ChildBeanDefinition 继承了 RootBeanDefinition 中现有的属性值。

最后我们从 Spring 容器中获取 User 和 Person,打印结果如下:

user = User{username=‘javaboy’, address=‘www.javaboy.org’}

person = Person{username=‘javaboy’, address=‘www.javaboy.org’, nickname=‘江南一点雨’}

可以看到,Person 确实继承了 User 的属性值。

RootBeanDefinition 和 ChildBeanDefinition 都可以被 GenericBeanDefinition 代替,效果一样,如下:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

MutablePropertyValues pvs = new MutablePropertyValues();

pvs.add(“username”, “javaboy”);

pvs.add(“address”, “www.javaboy.org”);

GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();

rootBeanDefinition.setBeanClass(User.class);

rootBeanDefinition.setPropertyValues(pvs);

ctx.registerBeanDefinition(“user”,rootBeanDefinition);

GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();

childBeanDefinition.setParentName(“user”);

childBeanDefinition.setBeanClass(Person.class);

childBeanDefinition.getPropertyValues().add(“nickname”, “江南一点雨”);

ctx.registerBeanDefinition(“person”, childBeanDefinition);

ctx.refresh();

User user = ctx.getBean(User.class);

Person person = ctx.getBean(Person.class);

System.out.println("user = " + user);

System.out.println("person = " + person);

运行结果如下:

user = User{username=‘javaboy’, address=‘www.javaboy.org’}

person = Person{username=‘javaboy’, address=‘www.javaboy.org’, nickname=‘江南一点雨’}

总结

三个工作日收到了offer,头条面试体验还是很棒的,这次的头条面试好像每面技术都问了我算法,然后就是中间件、MySQL、Redis、Kafka、网络等等。

  • 第一个是算法

关于算法,我觉得最好的是刷题,作死的刷的,多做多练习,加上自己的理解,还是比较容易拿下的。

而且,我貌似是将《算法刷题LeetCode中文版》、《算法的乐趣》大概都过了一遍,尤其是这本

《算法刷题LeetCode中文版》总共有15个章节:编程技巧、线性表、字符串、栈和队列、树、排序、查找、暴力枚举法、广度优先搜索、深度优先搜索、分治法、贪心法、动态规划、图、细节实现题

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

《算法的乐趣》共有23个章节:

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

  • 第二个是Redis、MySQL、kafka(给大家看下我都有哪些复习笔记)

基本上都是面试真题解析、笔记和学习大纲图,感觉复习也就需要这些吧(个人意见)

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

  • 第三个是网络(给大家看一本我之前得到的《JAVA核心知识整理》包括30个章节分类,这本283页的JAVA核心知识整理还是很不错的,一次性总结了30个分享的大知识点)

最新出炉,头条三面技术四面HR,看我如何一步一步攻克面试官?

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
力枚举法、广度优先搜索、深度优先搜索、分治法、贪心法、动态规划、图、细节实现题**

[外链图片转存中…(img-KQimh54C-1714753000547)]

《算法的乐趣》共有23个章节:

[外链图片转存中…(img-9v65DTLp-1714753000548)]

[外链图片转存中…(img-c0GF422H-1714753000548)]

  • 第二个是Redis、MySQL、kafka(给大家看下我都有哪些复习笔记)

基本上都是面试真题解析、笔记和学习大纲图,感觉复习也就需要这些吧(个人意见)

[外链图片转存中…(img-DO45dk2l-1714753000548)]

  • 第三个是网络(给大家看一本我之前得到的《JAVA核心知识整理》包括30个章节分类,这本283页的JAVA核心知识整理还是很不错的,一次性总结了30个分享的大知识点)

[外链图片转存中…(img-8kfdOnI3-1714753000548)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值