Spring或SpringBoot中注册自定义Bean或自定义扫描注册Bean

2018-11-16 / 1 阅读 / Java
问题
在Spring注解注入的基础上实现自定义的类注册,手动向Spring上下文注册我们自定义的Bean,和Spring自己注册的Bean同样效果
方式一:

如果使用普通Spring.xml配置的方式可以自己配置,这里不做解释,不过我用的是Springboot,这个方法直接pass

方式二:

BeanDefinitionRegistryPostProcessor的方式,采用自定义注解,给Class打打注解标记,也达不到我想要的效果,我的bean是继承某个类而不是注解,也pass。


 

不过根据方式二总算研究出一个全面的方法。
主要实现思路:
1、BeanDefinitionRegistryPostProcessor作为Spring预留的Bean注入接口类
2、自己手动扫描指定包(或子包)下的所有Class,并在1中预留的接口注入我的Bean。

 

BeanDefinitionRegistryPostProcessor好理解,百度一下就知道怎么使用。关键2中的扫描比较复杂(主要我的要求比较不同),如何扫描到自己的想要的类了?
关键用到:

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner配合BeanDefinitionRegistryPostProcessor可以完成Spring默认的一些注解注入的注册。但我的并没有使用Spring提供任何注解。一直扫描为0.

查找源码,在他的父类找到

Type过滤器集,一个是包含,另一个是排除。我这里只需要一个包含就就好。

继续找,一个公共注册过滤器的接口出现了。不错!

.    public void addIncludeFilter(TypeFilter includeFilter) {
        this.includeFilters.add(includeFilter);
    }

看来实现的外在条件都存在了,那就开始码代码了。

直接上代码:
package ****;

import ****.Control;
import ****.Screen;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.Configuration;
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;

@Configuration
public class BeanDefinitionRegistryConfig implements BeanDefinitionRegistryPostProcessor {
    public static final String SCREEN_PREFIX = "screen";

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 这边获取你想要扫描的基本跑路径
        String aPackage = this.getClass().getPackage().getName();
        int i = registryScreen(aPackage), beanDefinitionRegistry);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    // 具体的实现方法,
    private int registryScreen(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        // 这边实现自己的TypeFilter,只要父类是我想要的就反true。
        classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                if (metadataReader.getClassMetadata().getSuperClassName().equals(Screen.class.getName())) {
                    return true;
                }
                return false;
            }
        });

        // 这边因为我的Bean可能不同包可能同名,因此bean Id需要自己定义,如果明确不会重名,那使用spring默认命名器就好
        classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
            @Override
            public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
                String beanClassName = beanDefinition.getBeanClassName();
                String s = beanClassName.replaceAll(basePackage, SCREEN_PREFIX);
                return s.toLowerCase();
            }
        });
        return classPathBeanDefinitionScanner.scan(basePackage);
    }
}
相关推荐