java 强制接口实现为Spring组件

bmvo0sr5  于 2023-04-19  发布在  Java
关注(0)|答案(2)|浏览(123)

假设我声明了一个接口MyInterface,只有当它的实现是Spring组件时才有意义:

public interface MyInterface {
}

@Component
public class MyImpl1 implements MyInterface {
}

@Component
public class MyImpl2 implements MyInterface {
}

有没有其他方法可以做到这一点,而不需要用@Component注解每一个实现类?我希望实现自动注册,如果他们实现了MyInterface。

njthzxwz

njthzxwz1#

是的,你可以。你应该为你的接口MyInterface编写Bean后处理器,在启动spring应用程序之前,它会查找所有的类并找到所有实现该接口的类,然后将所有的类注册到ApplicationContext

nuypyhwy

nuypyhwy2#

自动注册特定接口的所有实现可以按如下方式完成。注意:对于大的类路径,对类路径(包括尚未加载的类)的完全扫描可能是耗时的。
创建一个@Configuration类,实现BeanDefinitionRegistryPostProcessorPriorityOrdered,如下所示。这将扫描并创建bean,其名称与实现类的包和类名相同。

import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RootBeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;

import com.example.demo.service.MyInterface;

@Configuration
public class BeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {

    private static Logger logger = LoggerFactory.getLogger(BeanFactoryPostProcessor.class);

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        Collection<URL> allPackagePrefixes = Arrays.stream(Package.getPackages()).map(p -> p.getName())
                .map(s -> s.split("\\.")[0]).distinct().map(s -> ClasspathHelper.forPackage(s)).reduce((c1, c2) -> {
                    Collection<URL> c3 = new HashSet<>();
                    c3.addAll(c1);
                    c3.addAll(c2);
                    return c3;
                }).get();
        ConfigurationBuilder config = new ConfigurationBuilder().addUrls(allPackagePrefixes)
                .addScanners(Scanners.SubTypes);
        Reflections reflections = new Reflections(config);
        Set<Class<? extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);
        
        classes.stream().forEach(clazz -> {
            String className = clazz.getName();
            BeanDefinition beanDefn= new RootBeanDefinition(className);
            registry.registerBeanDefinition(className, beanDefn);
            logger.debug("Registering bean {}", className);
        });
        
    }

    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // do nothing
        
    }
}

通过使用实现类的包和类名作为限定符来自动连接创建的bean,如下所示:

@Autowired
@Qualifier("com.example.demo.rest.MyImpl2")
MyInterface myInterface;

下面是对org.reflections:reflections的依赖:

<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.10.2</version>
</dependency>

相关问题