首页 > 其他分享 >SpingBoot原理

SpingBoot原理

时间:2024-06-30 20:57:55浏览次数:18  
标签:SpingBoot 配置文件 Spring 配置 class Bean 原理 public

配置优先级

SpringBoot配置的优先级从高到低依次为命令行参数、JNDI属性、Java系统属性、操作系统环境变量、外部配置文件、内部配置文件、注解指定的配置文件和编码中直接指定的默认属性。具体如下:

  1. 命令行参数:启动应用时,通过命令行指定的参数拥有最高优先级。例如,使用--server.port=8081会直接改变应用程序的端口,无论在什么配置文件中定义过该值。
  2. JNDI属性:这些属性由当前J2EE应用的环境提供,并具有第二优先级。
  3. Java系统属性:这些属性通过-D参数设置,并优先于操作系统环境变量。
  4. 操作系统环境变量:设置在操作系统级别的环境变量也具有较高的优先级。
  5. 外部配置文件:位于JAR包外部的配置文件(如application.propertiesapplication.yml)优先于内部的配置文件。特定环境的配置文件(如application-dev.properties)会覆盖通用配置文件(即application.properties)中的相应属性。
  6. 内部配置文件:在同一级目录下,不同后缀配置文件的优先级为:.properties最高,其次是.yml.yaml最低。相同后缀配置文件的优先级中,带环境名的配置文件(如application-dev.yml)高于不带环境名的(如application.yml)。
  7. 注解指定的配置文件:通过@PropertySource注解指定的配置文件优先级较低。
  8. 默认属性:通过SpringApplication.setDefaultProperties指定的默认属性拥有最低优先级。

下面是一个SpringBoot配置优先级的示例:

假设有以下配置文件:

  • application.properties(通用配置文件)
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
  • application-dev.properties(开发环境配置文件)
server.port=8081
spring.datasource.url=jdbc:mysql://localhost:3306/dev_test
  • application-prod.properties(生产环境配置文件)
server.port=8082
spring.datasource.url=jdbc:mysql://localhost:3306/prod_test
  • 命令行参数:--server.port=9090

在启动应用时,会按照以下顺序加载配置:

  1. 命令行参数:--server.port=9090
  2. JNDI属性、Java系统属性、操作系统环境变量等其他来源的配置选项。
  3. 外部配置文件:application.propertiesapplication-dev.propertiesapplication-prod.properties
  4. 内部配置文件:application.propertiesapplication-dev.propertiesapplication-prod.properties
  5. 注解指定的配置文件。
  6. 编码中直接指定的默认属性。

最终,应用程序的端口号为9090,数据源URL为jdbc:mysql://localhost:3306/dev_test

Bean管理

获取Bean

在Spring框架中,获取Bean的方法有多种,包括通过ApplicationContext、实现ApplicationContextAware接口、继承抽象类等方法。具体如下:

通过ApplicationContext获取Bean

  • 可以在初始化时保存ApplicationContext对象,然后通过这个对象获取Bean。例如,使用ClassPathXmlApplicationContext加载配置文件并获取Bean:
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    MyBean myBean = (MyBean) applicationContext.getBean("myBean");
    
  • 适用于独立应用程序和基于Web的应用程序,这种方法简单直接,但需要显式加载配置文件。

通过实现ApplicationContextAware接口获取Bean

  • 可以实现ApplicationContextAware接口并将ApplicationContext对象注入到实现类中,从而随时获取Bean。例如:
    public class SpringUtils implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
        
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            SpringUtils.applicationContext = applicationContext;
        }
        
        public static <T> T getBean(String beanName) {
            return (T) applicationContext.getBean(beanName);
        }
    }
    
  • 这种方法的优点是不需要显式加载配置文件,Spring会自动注入ApplicationContext。

通过继承抽象类获取Bean

  • 可以继承ApplicationObjectSupportWebApplicationObjectSupport抽象类,调用父类的getApplicationContext()方法获取Spring容器对象。例如:
    @Service
    public class SpringContextHelper extends ApplicationObjectSupport {
        public Object getBean(String beanName) {
            return getApplicationContext().getBean(beanName);
        }
    }
    
  • 这种方法适用于需要在Spring容器管理的对象内部获取其他Bean的场景。

通过BeanFactory获取Bean

  • 虽然不推荐,但可以通过BeanFactory来获取Bean。例如,使用已废弃的XmlBeanFactory类:
    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    MyBean myBean = (MyBean) beanFactory.getBean("myBean");
    
  • 由于XmlBeanFactory已被废弃,这种方法不推荐使用,且存在潜在的维护问题。

通过Spring提供的工具类获取ApplicationContext对象

  • 在基于Web的应用程序中,可以通过WebApplicationContextUtils工具类从ServletContext对象获取ApplicationContext对象,再通过它获取需要的类实例。例如:
    ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
    MyBean myBean = (MyBean) ac.getBean("myBean");
    
  • 这种方法适用于在Web应用程序中使用Spring框架的场景。

Bean作用域

Spring Bean的作用域定义了Bean在Spring容器中的生命周期和可见性,主要分为五种:singleton、prototype、request、session和application

作用域说明
singleton容器内同名称的bean只有一个实例(单例)(默认)
prototype每次使用该bean时会创建新的实例(非单例)
request每个请求范围内会创建新的实例(web环境中,了解)
session每个会话范围内会创建新的实例(web环境中,了解)
application每个应用范围内会创建新的实例(web环境中,了解)

 单例作用域(Singleton Scope)

  • 单例作用域是Spring的默认设置,在整个Spring IoC容器中只存在一个Bean实例。这意味着所有对该Bean的请求都会返回同一个实例。例如,在Spring配置文件中可以这样配置:
    <bean id="singletonBean" class="com.example.MySingletonBean" scope="singleton"/>
    
  • 适用于无状态的服务,如数据访问对象(DAO)、业务服务(Service)等,因为这些组件不需要存储特定于用户的信息,可以在多线程之间安全共享。

原型作用域(Prototype Scope)

  • 每次注入或通过getBean()方法调用时,都会创建一个新的Bean实例。这意味着每个请求得到的都是一个全新的对象。例如,在Spring配置文件中可以这样配置:
    <bean id="prototypeBean" class="com.example.MyPrototypeBean" scope="prototype"/>
    
  • 适用于需要频繁创建新对象的场景,如每次使用时需要新的状态或配置的Bean。

请求作用域(Request Scope)

  • 每个HTTP请求都会创建一个新的Bean实例,该实例仅在当前请求中有效,请求结束后即被销毁。这适用于需要在单个HTTP请求中保持状态的Bean。例如,在类上添加注解:
    @Component
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class MyRequestBean {
        // ...
    }
    
  • 适用于处理表单提交或执行某个请求特定操作的组件。

会话作用域(Session Scope)

  • 每个HTTP会话都会创建一个新的Bean实例,该实例在会话结束前一直有效。这适用于需要在多个HTTP请求之间保持状态的Bean。例如,在类上添加注解:
    @Component
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class MySessionBean {
        // ...
    }
    
  • 适用于需要跟踪用户会话信息的场景,如购物车或用户登录信息。

应用程序作用域(Application Scope)

  • 在ServletContext范围内,整个Web应用程序共享同一个Bean实例。该实例在应用程序启动时创建,应用程序关闭时销毁。例如,在类上添加注解:
    @Component
    @Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class MyApplicationBean {
        // ...
    }
    
  • 适用于需要在整个Web应用程序中共享的状态或资源,如全局缓存或配置信息。

第三方Bean

在Spring框架中,第三方Bean的管理是通过配置类和注解来实现的,使得开发者可以在不修改原始代码的情况下定义和管理这些Bean。具体如下:

使用@Bean注解管理第三方Bean

  • 环境准备:需要创建一个Spring项目,并添加对应的依赖。例如,要管理Druid数据源,需要在pom.xml中添加Druid的依赖:
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>
  • 配置类和@Bean注解:在配置类中使用@Bean注解标注的方法来创建和管理第三方Bean。比如,为Druid数据源创建一个DataSource Bean:
@Configuration
public class SpringConfig {
    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

使用独立的配置类

  • 导入式管理:通过在核心配置类中使用@Import注解,手动添加其他配置类。例如,可以将JdbcConfig导入到SpringConfig中:
@Configuration
public class JdbcConfig {
    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        // 相关配置
        return ds;
    }
}

@Configuration
public class SpringConfig {
    @Import(JdbcConfig.class)
    // 其他配置...
}
  • 扫描式管理:使用@ComponentScan注解自动加载对应包中的配置类。这种方法虽然简便,但可能隐藏性太强,不推荐使用。
@Configuration
@ComponentScan("com.itheima.config")
public class SpringConfig {}

第三方Bean的依赖注入

  • 简单类型依赖注入:使用@Value注解可以注入简单类型的值,如字符串、整数等。例如,注入数据库URL和用户名:
public class JdbcConfig {
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private String url;

    @Value("root")
    private String userName;

    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setUrl(url);
        ds.setUsername(userName);
        // 其他配置...
        return ds;
    }
}
  • 引用类型依赖注入:通过在Bean定义的方法中添加形参,Spring会自动装配同类型的Bean。例如,注入BookService:
@Bean
public DataSource dataSource(BookService bookService) {
    System.out.println(bookService);
    DruidDataSource ds = new DruidDataSource();
    // 属性设置
    return ds;
}

XML配置与注解配置的比对

  • 定义bean:XML配置使用标签;注解配置使用@Component及其衍生注解。
  • 依赖注入:XML配置通过标签设置属性;注解配置使用@Autowired、@Qualifier、@Value等。

SpringBoot原理

起步依赖

起步依赖是Spring Boot的核心特性之一,通过提供一系列预定义的依赖项集合来简化项目的搭建和依赖管理

起步依赖(Starter)在Spring Boot中起着至关重要的作用。它通过整合各种依赖库和自动配置,大大简化了开发者的工作。例如,当在项目中添加spring-boot-starter-web起步依赖时,会自动包含Spring MVC、Tomcat和其他Web开发所需的依赖,无需再手动逐个添加这些依赖。这样不仅提高了开发效率,还减少了因版本不兼容导致的问题。

起步依赖的原理是通过spring.factories文件和自动配置类来实现的。当项目引入某个Starter后,Spring Boot会在启动时读取META-INF/spring.factories文件中的配置,根据其中的自动配置类(如DataSourceAutoConfigurationWebMvcAutoConfiguration等)来自动配置相应的Bean。这些自动配置类通常包含一系列的条件注解(如@ConditionalOnClass@ConditionalOnMissingBean等),用于判断是否满足某些条件来决定配置哪些Bean。

除了使用官方提供的起步依赖外,Spring Boot还允许开发者自定义Starter。自定义Starter的命名通常遵循反向的格式,如官方的是spring-boot-starter-xxx,而自定义的则是xxx-spring-boot-starter。自定义Starter时,需要创建一个自动配置模块,并在其中定义相关的自动配置类和属性类,然后通过spring.factories文件将其与对应的Starter关联起来。

代码解释:

引入起步依赖:在项目的pom.xml文件中添加spring-boot-starter-web起步依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

自动配置类:当项目引入spring-boot-starter-web后,Spring Boot会在启动时读取META-INF/spring.factories文件,根据其中的自动配置类来自动配置相应的Bean。例如,WebMvcAutoConfiguration类会配置Spring MVC相关的Bean,如DispatcherServlet、ViewResolver等。

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(WebProperties.class)
@Import({ DispatcherServletAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    // ...
}

自定义属性类:除了自动配置类外,起步依赖还可能包含一些自定义的属性类,用于提供额外的配置选项。例如,WebProperties类提供了与Web相关的配置属性,如服务器端口号、上下文路径等。

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
    private Integer port;
    private String contextPath;
    // ...
}

使用起步依赖:在项目中可以直接使用起步依赖提供的Bean,无需手动创建或注入。例如,通过@Autowired注解注入一个RestTemplate实例:

@RestController
public class MyController {
    @Autowired
    private RestTemplate restTemplate;
    // ...
}

自定义Starter:除了官方提供的起步依赖外,开发者还可以自定义Starter。自定义Starter需要创建一个自动配置模块,并在其中定义相关的自动配置类和属性类,然后通过spring.factories文件将其与对应的Starter关联起来。

// 自动配置类
@Configuration
@ConditionalOnClass(MyService.class)
@Import(MyServiceAutoConfiguration.class)
public class MyServiceAutoConfiguration {
    // ...
}
// 属性类
@ConfigurationProperties(prefix = "myservice")
public class MyServiceProperties {
    private String url;
    // ...
}
// spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyServiceAutoConfiguration

Conditional注解

@Conditional注解是Spring中的一个强大的条件化配置工具,它用于控制特定Bean或配置类在满足某些条件时才被加载到Spring容器中。@Conditional可以应用在@Bean注解的方法上,也可以应用在整个@Configuration类上。具体如下:

@Conditional注解的作用

  • @Conditional注解的主要作用是提供一种机制,允许根据是否满足特定的条件来决定是否创建某个Bean或者是否执行某个配置块。这种条件可以是类路径中是否存在某个类、属性文件中的某个属性值、环境变量的值等等。

@Conditional的常见使用方式

  • @ConditionalOnClass:当类路径中存在指定的类时,条件匹配成功。例如,当需要根据项目是否使用了某个特定的数据库驱动来调整数据源的配置时,可以使用这个注解。
  • @ConditionalOnMissingClass:与@ConditionalOnClass相反,当类路径中不存在指定的类时,条件匹配成功。
  • @ConditionalOnBean:当Spring容器中存在指定类型的Bean时,条件匹配成功。这常用于基于容器中是否有某个特定Bean来调整配置。
  • @ConditionalOnMissingBean:与@ConditionalOnBean相反,当Spring容器中不存在指定类型的Bean时,条件匹配成功。
  • @ConditionalOnProperty:当指定的属性值满足条件时(如属性存在且其值为true),条件匹配成功。这常用于根据配置文件中的设置来决定是否启用某个配置。
  • @ConditionalOnExpression:基于SpEL表达式的条件判断,当表达式结果为true时,条件匹配成功。这提供了更灵活的条件判断方式。

自定义条件化配置

  • 除了上述的常见@Conditional注解外,Spring还允许开发者通过实现Condition接口或继承AbstractCondition类来创建自定义的条件化配置。这允许开发者根据具体的应用场景和需求来编写自己的条件判断逻辑。

代码示例:

@Configuration
public class MyConfiguration {
    
    @Bean
    @ConditionalOnClass(name = "com.example.MyService")
    public MyService myService() {
        return new MyService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "my.property", havingValue = "true")
    public MyComponent myComponent() {
        return new MyComponent();
    }
    
    @Bean
    @ConditionalOnExpression("${my.expression:false}")
    public MyOtherComponent myOtherComponent() {
        return new MyOtherComponent();
    }
}

标签:SpingBoot,配置文件,Spring,配置,class,Bean,原理,public
From: https://blog.csdn.net/weixin_74521994/article/details/139907697

相关文章

  • log 日志原理
    1)slf4j接口仅仅定义了接口,因此,需要绑定到具体的日志框架才可以打印日志出来,具体如何来做呢,引用一张slf4j官网上的图片: 具体的组合使用:slf4j-api,日志是打到了/dev/null里面,因此啥也打印不出来slf4j-api+logback-classic:使用的是logback,因为logback本身直接实现了slf4j的apis......
  • 【Python】 模型训练数据归一化的原理
    那年夏天我和你躲在这一大片宁静的海直到后来我们都还在对这个世界充满期待今年冬天你已经不在我的心空出了一块很高兴遇见你让我终究明白回忆比真实精彩                     ......
  • mybatis一级缓存、二级缓存的原理
    MyBatis的缓存机制分为两个级别:一级缓存和二级缓存。这两种缓存机制都有助于提高数据访问效率,减少对数据库的直接请求次数,但它们的工作原理和适用场景有所不同。一级缓存(Per-ExecutorTransactionalCaches)一级缓存也被称为“事务范围内的缓存”或者“执行器级别的缓存”。它是......
  • 快速检索【往期内容】:文献速递 + 分子动力学模拟 + 第一性原理计算 + 程序分享
    往期内容主要涵盖: 熔化温度 + 超导电性 + 电子化合物 + 分子动力学模拟 + 第一性原理计算 + 程序分享【1】熔化温度 +分子动力学+LAMMPS相关内容【文献分享】分子动力学模拟+LAMMPS+熔化温度+晶体缺陷+熔化方法LAMMPS文献:金属熔化行为的局域原子......
  • RDID、YUM相关原理
    总结RAID0,1,5,10,01的工作原理RAID0工作原理:数据条带化(Striping),将数据分块并分布到多个硬盘上。利用率:100%(无冗余)。冗余性:无冗余,任何一个硬盘故障都会导致数据丢失。性能:读写性能高。最少硬盘数:2个。RAID1工作原理:数据镜像(Mirroring),将数据完全复制到两个或多个......
  • Vue3 中的 v-bind 指令:你不知道的那些工作原理
    前言v-bind指令想必大家都不陌生,并且都知道他支持各种写法,比如<divv-bind:title="title">、<div:title="title">、<div:title>(vue3.4中引入的新的写法)。这三种写法的作用都是一样的,将title变量绑定到div标签的title属性上。本文将通过debug源码的方式带你搞清楚,v-bind指令是......
  • 文件系统(八):Linux JFFS2文件系统工作原理、优势与局限
    liwen012024.06.23前言在嵌入式Linux设备中,经常使用jffs2文件系统来作为参数区的文件系统格式。至于为什么要使用jffs2来作为参数区的文件系统,我猜大部分人都没有做过多的思考。jffs2在2021年被设计出来,距今已过二十多年,现在在嵌入式设备中它还在被大量使用、说明这套设计本身......
  • String字符串拼接原理
    分为三种情况字符串常量与字符串常量字符串常量之间的拼接操作在未加载到内存之前就已经完成了。在前端编译期间(即将.java源文件编译为.class字节码文件),会对字符串常量之间的拼接操作进行优化。对应的指令:可以看到对于s1和s2这两个局部变量,它们指向的是常量池中同一个对象,它......
  • 指令选择原理与实现方式
    概述编译器前端将源代码转换为等效形式的IR,IR经过优化器优化后传递到后端,由代码生成器将IR代码转换为汇编代码或目标代码在这个过程中,后端首先通过指令选择器目标机器支持的指令来实现IR指令至于指令的顺序,可由后续的指令调度器决定指令选择器指令选择器选择指令的基......
  • Vienna 整流器的基本原理及数学模型
    2.1Vienna整流器基本工作原理2.1.1主电路拓扑结构分析Vienna整流器系统的主电路包含用于升压的三相电感、三相桥臂和两个直流侧均压电容。通过有规律的对双向开关进行控制不仅能实现功率双向流动,还能使网侧电流时刻跟踪电网电压,使系统运行在高功率因数状态下。拓扑如图2......