SpingBoot原理

2024-06-24 09:36
文章标签 原理 spingboot

本文主要是介绍SpingBoot原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

配置优先级

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;@Overridepublic 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 {@Beanpublic 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 {@Beanpublic 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;@Beanpublic 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 {@Autowiredprivate 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原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1089770

相关文章

apache的commons-pool2原理与使用实践记录

《apache的commons-pool2原理与使用实践记录》ApacheCommonsPool2是一个高效的对象池化框架,通过复用昂贵资源(如数据库连接、线程、网络连接)优化系统性能,这篇文章主... 目录一、核心原理与组件二、使用步骤详解(以数据库连接池为例)三、高级配置与优化四、典型应用场景五、注意事

电脑系统Hosts文件原理和应用分享

《电脑系统Hosts文件原理和应用分享》Hosts是一个没有扩展名的系统文件,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应... Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

Spring框架中@Lazy延迟加载原理和使用详解

《Spring框架中@Lazy延迟加载原理和使用详解》:本文主要介绍Spring框架中@Lazy延迟加载原理和使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、@Lazy延迟加载原理1.延迟加载原理1.1 @Lazy三种配置方法1.2 @Component

spring IOC的理解之原理和实现过程

《springIOC的理解之原理和实现过程》:本文主要介绍springIOC的理解之原理和实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、IoC 核心概念二、核心原理1. 容器架构2. 核心组件3. 工作流程三、关键实现机制1. Bean生命周期2.

Redis实现分布式锁全解析之从原理到实践过程

《Redis实现分布式锁全解析之从原理到实践过程》:本文主要介绍Redis实现分布式锁全解析之从原理到实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景介绍二、解决方案(一)使用 SETNX 命令(二)设置锁的过期时间(三)解决锁的误删问题(四)Re

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持