SpringBoot之Starter组件原理

Posted by Kaka Blog on October 27, 2020

IOC加载原理

类 -> BeanDefinition -> BeanFactory -> Bean

1、基于配置文件

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

2、基于配置类

ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);

JavaConfigApplication.java@Configuration注解修饰,表示Java配置类,用@Bean修饰的方法,返回的结果在系统启动时会被装配到IOC容器里面。

public class User {
}
@Configuration
public class JavaConfigApplication {
    @Bean
    public User getUser() {
        return new User();
    }
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfigApplication.class);
        System.out.println(ac.getBean(User.class));
    }
}

或者在要加在的类名上加上@Component注解,在JavaConfigApplication.java增加@ComponentScan注解。这种方式启动会慢些。

@Component
public class User {
}
@Configuration
@ComponentScan
public class JavaConfigApplication {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfigApplication.class);
        System.out.println(ac.getBean(User.class));
    }
}

3、springboot启动

SpringApplication.run(Application.class, args);

其中Application类用@SpringBootApplication注解。

@ComponentScan注解

扫描启动器所在的包及其子包带有指定注解的类自动装配到bean容器里。会被自动装配的注解包括@Controller、@Service、@Component、@Repository等等。

@SpringBootConfiguration注解

@Configuration注解等价,所以在启动类中用@Bean修饰的方法,返回的对象也是会被注入到IOC容器里。其中利用反射的原理生成对象。

@EnableAutoConfiguration注解,重点研究

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 {};
}

AutoConfigurationPackage注解源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@Import注解

通过快速导入的方式实现把实例加入spring的IOC容器中。场景:@SpringBootApplication注解只会扫描当前类路径下的类,当引用第三方包时,需要加载第三方类实例时,可以用@Import导入。

在Spring中我们将对象添加到IOC容器中的方式有哪些:

  1. 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
  2. @Bean、[导入的第三方包里面的组件]
  3. 实现FactoryBean接口, 实现getObject方法,用@Component注入,可以动态注入,例如Mybatis
  4. @Import注解,快速给容器中导入一个组件

@Import三种用法

1、直接填class数组,静态导入

@Import({Registrar.class})

2、ImportSelector方式。返回需要导入的组件的全类名数组

实现ImportSelector接口,重写selectImports方法,不是把AutoConfigurationImportSelector导入到容器里,而是把selectImports返回结果导入到容器。

@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 全类路径
        return new String[]{User.class.getName()};
    }
}

3、ImportBeanDefinitionRegistrar方式,手动注册bean到容器中

导入的是实现了ImportBeanDefinitionRegistrar接口的类型。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        RootBeanDefinition user = new RootBeanDefinition(User.class);
        beanDefinitionRegistry.registerBeanDefinition("user", user);
    }
}

spring.factories文件

加载META-INF/spring.factories文件里的自动配置类。

org.springframework.boot.autoconfigure.EnableAutoConfiguration

所以加了@EnableAutoConfiguration注解后,在容器启动后,会自动扫描各个依赖包里面META-INF/spring.factories文件里的自动配置类。如果想要注入自定义第三方依赖,则需要再自定义包创建META-INF/spring.factories文件,在配置文件里配置org.springframework.boot.autoconfigure.EnableAutoConfiguration,值为Java配置类全路径,在Java配置类需要增加@ComponentScan注解,这就可以注入其它Bean。

@Conditional条件注解

按照一定的条件进行判断,满足条件给容器注册bean。例如Mybatis会使用@ConditionalOnProperty注解,判断是否配置spring.datasource.type信息,如果没有配置,则不会创建dataSource实例。

/META-INF/spring-autoconfigure-metadata.properties文件可以配置条件注入。例如Mybatis依赖iBatis,在mybatis-starter包有这样的配置:

com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration.ConditionalOnClass=org.apache.ibatis.session.SqlSessionFactory,org.mybatis.spring.SqlSessionFactoryBean