Springboot学习笔记-常用注入组件方式

Posted 舒山

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Springboot学习笔记-常用注入组件方式相关的知识,希望对你有一定的参考价值。

包扫描@ComponentScan+组件标注注解(@Controller@Service@Repository@Component)

包扫描不是必须的,指定包名后以指定的包名为准,比如指定包名为a:@ComponentScan("a"),即使b包中有标注@Controller等注解的bean也不注册。

包扫描注解除了默认的value()还有basePackages()basePackageClasses()等方法:

basePackages(): 指定扫描的包名(前缀)

basePackageClasses():如果指定为A.class,那么会扫描A类所在包的类。

includeFilters():将所指定的类注入容器。
excludeFilters():将所指定的类排除。

@ComponentScan.Filter中的FilterType除了给定的类型,还可以自定义:type=FilterType.CUSTOM,指定的类实现TypeFilter接口即可,同时注意不适用默认拦截器useDefaultFilters = false

比如,定义和注入配置文件映射类需要使用注解ConfigurationPropertiesEnableConfigurationProperties,那么当配置文件变多的时候,注入起来就比较麻烦了@EnableConfigurationProperties(A.class, B.class, C.class...),所以可以使用自定义过滤器来注入所有的配置文件映射类,思路很简单,只要标注注解ConfigurationProperties就将其注入:

public class IncludePropertiesFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        return metadataReader.getAnnotationMetadata().hasAnnotation(EnableConfigurationProperties.class.getName());
    }
}

在主启动类上开启过滤规则:

@SpringBootApplication
@ComponentScan(useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM, classes = IncludePropertiesFilter.class))
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@Bean

可以放在方法和注解上。

一般放在标有@Configuration类中的方法上。如:

@Import

只能用在类上,最简单直观,将A注入:

虽然直观,但需要批量注入就有点麻烦,@Import提供了高级功能:

ImportSelector

ImportSelector是个接口,它只有一个方法:

String[] selectImports(AnnotationMetadata importingClassMetadata);

返回值是需要注入的类型全类名,入参是指和@Import并列的全部注解信息,比如有个实现类:

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        if (importingClassMetadata.hasAnnotation(UsesJava8.class.getName())) {
            return new String[]{A.class.getName()};
        }
        return new String[0];
    }
}

表示只有@UsesJava8@Import同时标注时才注入A,以下情况会生效:

@SpringBootApplication
@Import(MyImportSelector.class)
@UsesJava8
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar也是个接口,它只有一个方法:

	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

简单实现如下:

public class MyImportSelector implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        registry.registerBeanDefinition("IThreadPool", new RootBeanDefinition(A.class));
    }
}

调用:

@SpringBootApplication
@Import(MyImportSelector.class)
@UsesJava8
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

注册工厂Bean

和普通Bean不一样,普通的是通过调用构造器,而工厂是实现FactoryBean泛型接口,泛型为真正类型,通过getObject方法获取实例:

@Configuration
public class MyConfiguration {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        // com.y.pojo.MyConfiguration$A
        System.out.println(context.getBean("aFactoryBean").getClass().getName());
        // com.y.pojo.MyConfiguration$AFactoryBean
        System.out.println(context.getBean("&aFactoryBean").getClass().getName());
        
        A a1 = context.getBean("aFactoryBean", A.class);
        A a2 = context.getBean("aFactoryBean", A.class);
        // false
        System.out.println(Objects.equals(a1, a2));
    }

    @Bean
    public AFactoryBean aFactoryBean() {
        return new AFactoryBean();
    }

    private static class A {
    }

    private static class AFactoryBean implements FactoryBean<A> {

        @Override
        public A getObject() throws Exception {
            return new A();
        }

        @Override
        public Class<?> getObjectType() {
            return A.class;
        }

        @Override
        public boolean isSingleton() {
            return false;
        }
    }
}

以上是关于Springboot学习笔记-常用注入组件方式的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot常用注解及外部jar包注入方式

Java Spring学习笔记----Bean的依赖注入

Springboot学习笔记-条件化注入

正确理解springboot的常用注入方式

[SpringBoot2]原生组件注入_原生注解与Spring方式注入

springBoot学习笔记初识springBoot