springBoot starter原理

通常搭建一个基于spring的web应用,我们需要做以下工作:

  1. pom文件中引入相关的jar包,包括spring、spring mvc、redis、mybatis、log4j、mysql-connector-java等相关的jar
  2. 配置web.xml,listenter配置、Filter配置、Servlet配置、log4j配置、error配置
  3. 配置数据库连接、配置spring事务
  4. 配置视图解析器
  5. 开启注解、自动扫描功能
  6. 配置完成后部署tomcat、启动调试

springBoot拥有很多方便使用的starter,spring提供的stater命名规范spring-boot-stater-xxx.jar,第三方提供的starter命名规范xxx-spring-boot-stater.jar。比如spring-boot-starter-log4j、mybatis-spring-boot-starter.jar等,各自代表了一个相对完整的功能模块。

以mybatis-spring-boot-starter为例,我们分析一下starter做了哪些操作

可以看到在mybatis-spring-boot-starter中,并没有任何的源码,只有一个pom文件,它的作用就是帮我们引入mybatis-spring-boot-autoconfigure这个包

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnBean({DataSource.class})
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration {
    private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class);
    @Autowired
    private MybatisProperties properties;
    @Autowired(
        required = false
    )
    private Interceptor[] interceptors;
    @Autowired
    private ResourceLoader resourceLoader = new DefaultResourceLoader();
    @Autowired(
        required = false
    )
    private DatabaseIdProvider databaseIdProvider;


    public MybatisAutoConfiguration() {
    }


    @PostConstruct
    public void checkConfigFileExists() {
        if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
            Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
            Assert.state(resource.exists(), "Cannot find config location: " + resource + " (please add config file or check your Mybatis " + "configuration)");
        }


    }


    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }


        factory.setConfiguration(this.properties.getConfiguration());
        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }


        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }


        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }


        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }


        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }


        return factory.getObject();
    }


    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        ExecutorType executorType = this.properties.getExecutorType();
        return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
    }

@Configuration @Bean一起使用就可以创建一个基于java代码的配置类,用来代替相应的xml配置文件。MybatisAutoConfiguration自动帮我们生成了SqlSessionFactory这些Mybatis的重要实例并交给spring容器管理,从而完成bean的自动注册。

从MybatisAutoConfiguration这个类中使用的注解可以看出,要完成自动配置是有以来条件的。

这些是springboot特有的,常见的条件依赖注解有:

  • @ConditionalOnBean,仅在当前上下文中存在某个bean时,才会实例化这个bean
  • @ConditionalClass,某个class位于类路径上,才会实例化这个bean
  • @ConditionalOnExperssion,当表达式为true时,才会实例化这个Bean
  • @ConditionalOnMissingBean,仅当当前上下文不存在某个bean时,才会实例化这个Bean
  • @ConditionalOnMissingClass,某个class在类路径上不存在的时候,才会实例化这个Bean
  • @ConditionalOnNotWebApplication,不是web应用时才会实例化这个Bean
  • @AutoConfigureAfter,在某个bean完成自动配置后实例化这个bean
  • @AutoConfigureBefore,在某个bean完成自动配置前实例化这个bean

所以要完成Mybatis的自动配置,需要在类路径中存在SqlsessionFactory.class、SqlSessionFactoryBean.class这两个类,需要存在DataSource这个Bean且bean完成自动注册
bean参数的获取

  • @EnableConfigurationProperties注解的作用是使@ConfigurationProperties注解生效
  • @ConfigurationProperties 注解的作用是把yml或者properties配置文件转换为bean

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

在springboot项目中,启动类通常都有@SpringBootApplication注解

@SpringBootApplication注解中又包含

  • @SpringBootConfiguration == @Configuration,标识被注解的类将成为一个bean的配置类
  • @ComponentScan 扫描并加载符合条件的组件,比如@Controller @Service等
  • @EnableAutoConfiguration 这个注解借助@Import的支持,收集和注册依赖包中相关的bean定义

虽然根据说明我们应该看EnableAutoConfigurationImportSelector。但是该类在SpringBoot 1.5.x版本已经过时了。因此我们来看下它的父类AutoConfigurationImportSelector

AutoConfigurationImportSelector首先实现了DeferredImportSelector接口,这个接口继承了ImportSelector。ImportSelector接口主要是为了导入@Configuration的配置项,而DeferredImportSelector是延期导入,当所有的@Configuration都处理后才会执行。我们主要看下AutoConfigurationImportSelector的selectImports方法:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    private static final String[] NO_IMPORTS = new String[0];
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    private ConfigurableListableBeanFactory beanFactory;
    private Environment environment;
    private ClassLoader beanClassLoader;
    private ResourceLoader resourceLoader;


    public AutoConfigurationImportSelector() {
    }


    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                configurations = this.removeDuplicates(configurations);
                configurations = this.sort(configurations, autoConfigurationMetadata);
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return (String[])configurations.toArray(new String[configurations.size()]);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> 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;
    }
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();


    try {
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
        ArrayList result = new ArrayList();


        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }


        return result;
    } catch (IOException var8) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
    }
}

可以看到该方法会使用SpringFactoryLoader,它会读取META-INF/spring.factories文件里所配置的EnableAutoConfiguration。经过exclude和filter等操作,最终确定要装配的类

自动配置的关键几步,以及相应的注解如下:

  1. @Configuration与@Bean -》基于java代码的bean配置
  2. @Conditional -》设置自动配置条件依赖
  3. @EnableConfigurationProperties 与@ConfigurationProperties 读取配置文件转换为bean
  4. @EnableAutoConfiguration、@AutoConfiguration Package 、@Import实现bean的发现与加载

让一个普通类交给spring 容器管理,通常有以下方法

  1. 使用@Configuration与@Bean注解
  2. 使用@Controller、@Service、@Repository
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot Starter是一种Spring Boot项目中的依赖项,它可以自动配置和装配应用程序所需的所有组件和库。它的原理是通过在类路径中查找特定的依赖项,然后根据这些依赖项自动配置应用程序。这些依赖项通常是Spring Boot自带的,也可以是第三方库。Spring Boot Starter可以大大简化应用程序的配置和部署过程,提高开发效率。 ### 回答2: SpringBoot是一个非常流行的框架,它能够让我们快速而轻松地构建应用程序。而 SpringBoot StarterSpringBoot 的一个特性,它为我们的应用程序提供了很多便利。 首先,我们要明确一点,SpringBoot Starter并不是一个库或类的概念,而是一种做法,一种约定。其实SpringBoot Starter就是一个Spring Boot 应用需要的各种依赖,这些依赖以一种常规的方式打包在一起,并且和SpringBoot本身一样,使用自动配置。 SpringBoot Starter解决了SpringBoot应用的依赖问题,使用起来非常方便,只需在项目的pom.xml中引入所需要的Starter,就会自动添加相关的依赖。 在SpringBoot应用程序中,我们可能会使用到各种不同的技术,比如security、mybatis、redis等等,而每个技术都有自己的一堆依赖。如果我们要手动一个个去添加依赖,那么就需要耗费大量的时间和精力。这时候就有了SpringBoot Starter,我们只需要引入对应的Starter,就能在不用任何其他的配置情况下,使用这些技术,非常的方便。 除了提供依赖管理外,SpringBoot Starter还提供了自动配置。Spring Boot在启动时就会自动加载各个Starter的配置,为我们减少了很多手动编写配置的工作。如果我们需要自定义某个Starter的配置,可以在自己的应用程序中添加对应的配置,Spring Boot会自动使用我们的配置替换掉Starter中的默认配置。这样,我们就可以很灵活地使用各种技术,并且可以根据需要定制自己的应用程序。 总之,SpringBoot Starter是为了让我们更加方便地构建应用程序而生的,它解决了应用程序中依赖和配置的问题,让我们只需专注于业务逻辑的开发。 ### 回答3: Spring Boot是一款基于Spring框架的、用于构建微服务应用的工具。它可以帮助开发人员快速、高效地构建应用程序,同时还可以提供强大的自动化配置功能及一些其他的便捷特性。而Spring Boot Starter则是Spring Boot的一个核心组成部分,它是一种为Spring Boot应用程序提供预设的依赖项和配置的机制。 简单来说,Spring Boot Starter就是一些打包好的依赖包,通过引入这些Starter,我们可以轻松地创建出去除Spring Boot默认依赖之外的其他依赖项,并且Spring Boot会自动化配置这些新依赖。在引入Spring Boot Starter的过程中,Spring Boot会根据启动时的Classpath中所含有的相关配置信息,自动化地配置Spring应用程序的一些参数。这些自动化配置的参数包括但不限于web服务器配置、数据库配置、缓存配置以及安全配置等等。 Spring Boot Starter可以被看做是一个开箱即用的Spring应用程序框架,通过使用起来,开发人员可以极大地提高应用程序的开发效率,同时也减少了一些代码冗余。对于像繁琐的配置和依赖项协调等枯燥的工作,Spring Boot Starter可以充分地发挥出自己的优势。这些Starter可以使我们更便捷地实现一些特定的功能,从而能够更加高效地开发出高质量的应用程序。 总之,Spring Boot Starter是一个非常优秀的解决方案,通过它,开发人员可以省去很多繁琐、冗杂的工作,极大地提高了应用程序的开发效率和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值