springboot生成自定义beanNameGenerator且手写时容易出现的bug

附上我的github项目源码: https://github.com/hzprivate/studyAll   查看 springboot-beanNameGenerator项目

阅读spring官方文档时,看到了一个beanNameGenerator:

当一个组件作为扫描过程的一部分被自动检测时,它的bean名称由该扫描程序所知道的BeanNameGenerator策略生成。默认情况下,任何包含名称值的Spring构造型注释(@Component、@Repository、@Service和@Controller)都将该名称提供给相应的bean定义。
如果这样的注释不包含名称值或任何其他检测到的组件(例如由自定义过滤器发现的组件),则默认bean名称生成器将返回未大写的非限定类名。例如,如果下面的组件类

 

 

于是根据官方文档的例子,顺便翻了下beanNameGenerator源码,看了下如何生成默认bean名称

 

关键这四行代码 简单易懂。

于是马上新建springboot项目,手写自己的命名规则。

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;

/**
 * 自定义 组件命名规则 返回全限定名称
 * @author hz
 * @create 2020-04-09
 */
public class MyNameGenerator implements BeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {

            //获取全限定名称
            String beanClassName = beanDefinition.getBeanClassName();
//        //获取类名
//        String shortClassName = ClassUtils.getShortName(beanClassName);
            //小写首字母
//        String decapitalize = Introspector.decapitalize(shortClassName);
            return beanClassName;


    }
}
import com.springboot.beanname.generator.MyNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author hz
 * @create 2020-04-10
 */
@Configuration
@ComponentScan(basePackages = "com.springboot.beanname.bean.bean1",nameGenerator = MyNameGenerator.class)
public class AppConfig {

}

 

美滋滋的开启我的项目,打印所有的bean对象看下是不是生成了自己想要的规则名称。然后exceuse me? 为什么产生了两个bean对象,我的规则事实证明成功了,但是为什么默认规则的也执行了。这就很尴尬了。如果这样。那我们反过来想。项目里有两个同名类。并且都随容器生成bean对象。那就会报beanName对象重复错误。那这个自定义就没有任何意义。

最后调试了半天 BeanNameGenerator 源码,我以为在这接口前又执行了什么生成bean对象操作。最后把问题定位到了启动类里的 @SpringBootApplication注解。 点开进去。发现原来。他这里有扫描注解。哎、头疼。启动类执行时根据默认命名规则生成bean对象到容器。我的配置类 AppConfig 也会随着项目启动根据自己的命名规则生成Student bean对象到容器。所以容器产生了不同的两个Student对象名称。

继续修改代码。在启动类上用自己的ComponentScan。excludeFilters :用自定义过滤规则MyTypeFilter  过滤掉com.springboot.beanname.bean.bean1下的扫描对象Student

import com.springboot.beanname.filter.MyTypeFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;

//@SpringBootApplication //(相当于如下三个注解)
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class)})
public class BeannameApplication {
    public static void main(String[] args) {
        //启动Spring Boot项目的唯一入口
        SpringApplication springApplication =new SpringApplication(BeannameApplication.class);
        springApplication.addListeners(new ApplicationStartup());
        springApplication.run(args);
    }

}

 

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**
 * ComponentScan 扫描 指定过滤规则
 * @author hz
 * @create 2020-04-13
 */
public class MyTypeFilter implements TypeFilter {
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        Resource resource = metadataReader.getResource();
        String className = classMetadata.getClassName();
        // 检测名字包含 com.springboot.beanname.bean.bean1 的bean
        if(className.contains("com.springboot.beanname.bean.bean1")){
            return true;
        }
        return false;
    }
}

再次启动。大功告成。com.springboot.beanname.bean.bean1下的对象 用自定义规则。其余的用默认规则。并且两个同名Student 也不会报beanName重复错误了

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值