zoukankan      html  css  js  c++  java
  • 聊聊spring bean名称命名的那些事儿

    前言

    用了多年spring,一直想当然把spring默认的beanName当成是类名的首字母小写,比如HelloService其beanName为helloService。直到有天对接了供方厂商的接口,他有个类形如ABService,于是用

    getBean(“aBService”) 
    

    的方式获取bean,结果取到是null,一开始以为是ABservice没注入,后面采用

    getBean(ABService.class) 
    

    能成功获取到bean,说明ABService是有注入到IOC容器中,但是为啥用aBService获取不到bean?于是就用如下代码段,打印出相应ABService对应的beanName

     applicationContext.getBeansOfType(ABService.class).forEach((beanName,bean)->{
                System.out.println(beanName + ":" + bean);
            });
    

    打印出来的结果,如下

    ABService:com.github.lybgeek.ABService@245b6b85
    

    beanName竟然是ABService,这就和之前的想当然有出入。于是只好查看源码

    源码查看

    源码查看有2种方式,本文的示例是springboot项目

    方法一:从main方法直接调试断点

    beanName.jpg
    从图可以看出如果是以扫描注解注入形式,其beanName的生成规则是由

    org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName
    

    决定。

    ps: 这种直接从main启动类调试起,比较适用于时间比较多,或者排查毫无头绪

    方法二:带着问题查看,靠猜加验证的方式

    利用idea的find Usage查找引用,比如ABService的注解@service,我们可以直接查看哪个引用到@Service,再猜测下beanName的生成规则
    在这里插入图片描述
    通过猜,我们基本上就可以定位出比较符合我们需求的方法

    源码验证

    从上面的分析,我们可以知道如果是扫描bean注解注入的方式,其生成beanName规则,是在

    org.springframework.context.annotation.AnnotationBeanNameGenerator
    

    其生成规则代码如下

    @Override
    	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    		if (definition instanceof AnnotatedBeanDefinition) {
    			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
    			if (StringUtils.hasText(beanName)) {
    				// Explicit bean name found.
    				return beanName;
    			}
    		}
    		// Fallback: generate a unique default bean name.
    		return buildDefaultBeanName(definition, registry);
    	}
    
    

    从代码段,我们可以看出,注解上有取名,比如@Service(“abService”),则beanName为abService,如果没有取名,则看

    protected String buildDefaultBeanName(BeanDefinition definition) {
    		String beanClassName = definition.getBeanClassName();
    		Assert.state(beanClassName != null, "No bean class name set");
    		String shortClassName = ClassUtils.getShortName(beanClassName);
    		return Introspector.decapitalize(shortClassName);
    	}
    
    public static String decapitalize(String name) {
            if (name == null || name.length() == 0) {
                return name;
            }
            if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                            Character.isUpperCase(name.charAt(0))){
                return name;
            }
            char chars[] = name.toCharArray();
            chars[0] = Character.toLowerCase(chars[0]);
            return new String(chars);
        }
    
    

    其实从代码我们就很容易看出答案了,如果类名前两个或以上个字母都是大写,则beanName和类名就一样了,不会进行首字母小写转换。

    decapitalize这个方法的注释也写得很清楚,注释如下

    /**
         * Utility method to take a string and convert it to normal Java variable
         * name capitalization.  This normally means converting the first
         * character from upper case to lower case, but in the (unusual) special
         * case when there is more than one character and both the first and
         * second characters are upper case, we leave it alone.
         * <p>
         * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
         * as "URL".
         *
         * @param  name The string to be decapitalized.
         * @return  The decapitalized version of the string.
         */
    

    总结

    通过扫描bean注解注入IOC时,如果不指定bean名称的默认规则是类名的首字母小写,如果类名前两个或以上个字母都是大写,那么bean名称与类名一样。

    其实这个细节可能懂的都懂,本文的彩蛋主要是分享一下平时查看源码的一点心得吧,哈哈

  • 相关阅读:
    应用网络电视机顶盒通过宽带网络代替数字电视
    该公众号暂时无法提供服务请稍后再试
    有点坑爹的GDALComputeRasterMinMax函数
    微信硬件平台框架说明及接入流程
    微信硬件设备接入接口协议
    微信思维
    百度SEO建议
    公众平台调整SSL安全策略,请开发者注意升级
    微信支付开发教程
    .net文件分片上传,断点续传
  • 原文地址:https://www.cnblogs.com/linyb-geek/p/14926001.html
Copyright © 2011-2022 走看看