原理--springboot 自动装配

目录

一、起步依赖

二、自动装配

2.1、基于java代码的bean配置--@Configuration在@SpringbootApplication中的作用

2.2、自动装配条件依赖

2.3、bean参数获取

2.4、bean发现(重点看)

ps: bean加载


一、起步依赖

二、自动装配

2.1、基于java代码的bean配置

@Configuration 和 @Bean 用来代替xml中的配置文件,创建Bean并将bean的控制权交给spring管理;


    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${drivername}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${password}"/> 
    </bean>
 
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:com/chen/mapper/*.xml"/>
    </bean>
    
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>

相当于用基于java代码的配置方式:

@Configuration  
public class Conf {  
    @Bean  
    public DataSource myDataSource() {   
        return xxxBuilder.create().build();  
    }  
    @Bean   
    public SqlSessionFactor mySqlSessionFac(@Qualifier DataSource dataSource) {  
        SqlSessionFactor fac= new SqlSessionFactor ();
        fac.setDataSource(dataSource);
        return fac.getObject();  
    }  
}

2.2、自动装配条件依赖

要完成自动配置是有依赖条件的,需要在类路径中存在SqlSessionFactory.class、SqlSessionFactoryBean.class这两个类,需要存在DataSource这个bean且这个bean完成自动注册。

@Configuration

//某个class位于类路径上,才会实例化这个Bean
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})

//仅在当前上下文中存在某个bean时,才会实例化这个Bean
@ConditionalOnBean({DataSource.class})

@EnableConfigurationProperties({MybatisProperties.class})

//在某个bean完成自动配置后实例化这个bean
@AutoConfigureAfter({DataSourceAutoConfiguration.class})

public class MybatisAutoConfiguration {
   
    private final MybatisProperties properties;

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        //....
        return factory.getObject();
    }
   

}

2.3、bean参数获取

到此我们已经知道了bean的配置过程,但是还没有看到springboot是如何读取yml或者properites配置文件的的属性来创建数据源的?靠 @EnableConfigurationProperties 注解;

@ConfigurationProperties注解的作用是把yml或者properties配置文件转化为bean。

@EnableConfigurationProperties注解的作用是使@ConfigurationProperties注解生效。

如果只配置@ConfigurationProperties注解,在spring容器中是获取不到yml或者properties配置文件转化的bean的。

@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class MybatisProperties  {
    private ClassLoader classLoader;
    private String name;
    private boolean generateUniqueName;
    private Class<? extends DataSource> type;
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private String jndiName;
    ...

}

2.4、bean发现

springboot默认扫描启动类所在的包下的主类与子类的所有组件,但并没有包括依赖包的中的类,那么依赖包中的bean是如何被发现和加载的?靠 @SpringBootApplication 注解;

我们可以把 @SpringBootApplication 看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration


@ComponentScan(
    excludeFilters = {
        @Filter(
          type = FilterType.CUSTOM,
          classes = {TypeExcludeFilter.class}
        ), 
        @Filter(
          type = FilterType.CUSTOM,
          classes = {AutoConfigurationExcludeFilter.class}
        )
    }
)

public @interface SpringBootApplication {
    ... ...
}

@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类

@ComponentScan:注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean;

@EnableAutoConfiguration :启用 SpringBoot 的自动配置机制

@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导入需要自动配置的组件。

@AutoConfigurationPackage的作用就是自动配置的包; 进入@AutoConfigurationPackage,发现也是引入了 @Import({Registrar.class})注解,点进 Registrar.class 的代码如下:

Registrar:登记员

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, 
new String[]{(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()});
        }
 
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
        }
    }

这两句代码的作用就是加载启动类所在的包下的主类与子类的所有组件注册到spring容器,这就是前文所说的springboot默认扫描启动类所在的包下的主类与子类的所有组件。

那问题又来了,要搜集并注册到spring容器的那些beans来自哪里?

进入 AutoConfigurationImportSelector类,

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
 
...
 
}

SpringFactoriesLoader.loadFactoryNames方法调用loadSpringFactories方法从所有的jar包中读取META-INF/spring.factories文件信息。

下面是spring-boot-autoconfigure这个jar中spring.factories文件部分内容,其中有一个key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值定义了需要自动配置的bean,通过读取这个配置获取一组@Configuration类。  

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
 
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition
 
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
oorg.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

每个xxxAutoConfiguration都是一个基于java的bean配置类。实际上,这些xxxAutoConfiguratio不是所有都会被加载,会根据xxxAutoConfiguration上的@ConditionalOnClass等条件判断是否加载。

总结:SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。

​​​​​​​

 

ps: bean加载

如果要让一个普通类交给Spring容器管理,通常有以下方法:

1、使用 @Configuration与@Bean 注解

2、使用@Controller @Service @Repository @Component 注解标注该类,然后启用@ComponentScan自动扫描

3、使用@Import 方法

springboot中使用了@Import 方法

@EnableAutoConfiguration注解中使用了@Import({AutoConfigurationImportSelector.class})注解,AutoConfigurationImportSelector实现了DeferredImportSelector接口,

DeferredImportSelector接口继承了ImportSelector接口,ImportSelector接口只有一个selectImports方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值