深入源码Bean的定义
我们都知道@ComponentScan注解,扫描路径,把bean注入到springIoc容器中。但是你了解过bean声明的过程么。
下面新建三个类,分别为测试类。配置类和一个简单User类
配置类
user类
我们通过main方法可以看到已经顺利拿到了user这个bean并且打印出来了。那你知道为什么我获取user的bean能获取到么,获取其他名字呢。为什么这个名字偏偏为user,别急,下面我们一探究竟。
当我初始化spring容器的时候,可以看到我去加载了配置类。也就是Config类,当前类里拥有两个注解
@Configuration和@ComponentScan
我们都知道@ComponentScan是扫描我指定的包下的bean注入到容器中,如果我不写路径,那默认就是当前包以下,我们可以点进去注解里面看里面有什么属性
里面有一个属性是nameGenerator(),看名字我们就不难猜测这是名字定义,可以点进去这个class看一下
点进去发现当前是一个接口,那么我们肯定是要看他的实现类,可以发现他的实现类有两个,我们主要是注解注入bean,那我们肯定点进去第一个实现类,看他做了什么操作
为了验证,我们可以打一个debug,然后debug运行我们的main方法,就会发现进入此实现类了
可以看到源码里首先判断是否属于注解bean,如果是则执行里面的一个determineBeanNameFromAnnotation方法,否则会执行最下面的buildDefaultBeanName方法,那我们user类拥有注解@Comment,那肯定会进入第一个determineBeanNameFromAnnotation方法,我们可以跟进去继续看里面都有什么操作。
可以看到,当前拿到@Comment注解,而我们知道有这个注解的只有User类,并且已经拿到注解里的属性值attributes,转为map,当前注解没有赋值bean的名称,所以value对应的是空。那么往下走就可以看到返回的是null
回到这里返回的beanName是null那么if (StringUtils.hasText(beanName))判断非空的时候肯定为false,所以肯定会执行下面的buildDefaultBeanName(definition, registry);方法,继续深入方法
发现拿到了当前类的全路径名,com.example.demo.config.pojo.User
然后执行工具类ClassUtils.getShortName(beanClassName)方法,这个方法其实就是截取获得当前类名
会拿到当前类名,也就是User,然后执行Introspector.decapitalize(shortClassName)方法,这个方法就是首字母小写,可以深入查看
做完处理然后返回,这样最终返回的bean的名字就是user,也就是我们根据user可以获取到这个bean了,既然知道原理是这样获得的,那么我们自己写一个类继承他这个接口,生产我们自定义名字岂不是很轻松。怕啥来啥,说来就来。
新建CustomBeanName类我们也是实现底层实现的BeanNameGenerator接口,重写generateBeanName方法,为了演示,很简单的只返回了没有value的情况下在原来的名称前加一个my字符串
然后配置类修改成自定义的bean生成
运行main方法看执行效果
这时候发现报错,哦,对,现在是我自定义的bean名称,前面应该加my,修改为myuser在看执行效果
这时候发现容器中已经存在这个bean了,并且名字是我们刚刚自定义的,大功告成。
本人也是小白,有不对的地方欢迎大佬指出。
苏格拉底说过,未经省察的人生没有价值。