SpringBoot自动装配

112 阅读2分钟

创建IOC容器中bean的几种方式

  • @ComponentScan扫描指定包路径下的被@Component、@Controller、@Service、@Repository标注的类,都会创建bean并交给ICO容器管理,使用时通过@Autowired引入。@SpringBootApplication复合了@ComponentScan,所以会自动扫描启动类同目录下的所有类

MyClass.java

@Component
@ConfigurationProperties(prefix = "myclass")
public class MyClass {
    private Integer id;
    private String name;
// 省略构造、get、set、toString方法
}

application.yaml

myclass:
  id: 1
  name: abc

ApplicationTests.java

@SpringBootTest
class ApplicationTests {
    @Autowired
    private MyClass myclass;
    @Test
    public void test() {
        System.out.println(myclass.getId());
    }
}
  • @Configuration创建配置类,在配置类中被@Bean标注的方法返回的对象会交给ICO容器管理,@ComponentScan也是定义在@Configuration配置类上的。这种方式取代了Spring中用xml配置bean的方式
@Configuration
public class MyClassConfig {
    @Bean
    public MyClass myclass() {
        return new MyClass();
    }
}
  • @Import的3种用法,也用在配置类上。
  1. 直接导入需要的类
@Configuration
@Import(MyClass.class)
public class MyClassConfig {

}
  1. 导入实现了ImportSelector接口的类,该类的selectImports方法返回需要导入类的全类名
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {MyClass.class.getName()};
    }
}
@Configuration
@Import(MyImportSelector.class)
public class MyClassConfig {

}
  1. 导入实现ImportBeanDefinitionRegistrar接口的类,在registerBeanDefinitions方法中进行bean注册
public class MyClassRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //定义bean
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(MyClass.class);
        //注册bean
        registry.registerBeanDefinition("myclass", rootBeanDefinition);
    }
}
@Configuration
@Import(MyClassRegistrar.class)
public class MyClassConfig {

}
  • 自动装配

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。在项目中引入对应的 starter,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。

启动类的@SpringBootApplication是@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan的组合,其中@EnableAutoConfiguration是自动装配的核心注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

其中由@Import引入了AutoConfigurationImportSelector类,该类中的selectImports方法用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

image.png

META-INF/spring.factories文件部分如下:

image.png 格式为:接口全路径名=实现类全路径名。多个实现类用逗号分隔

随后还会经过@ConditionalOnXxx条件过滤,按需加载,该系列注解是在配置类的方法上使用