springboot引入

springboot

最近在学习springboot,记录一些学习笔记。

配置优先级

springboot的配置优先级如下(从高到低):

  1. 命令行参数
1
java -jar app.jar --server.port=8080
  1. java系统属性
1
java -Dserver.port=8080 -jar app.jar
  1. properties文件
1
server.port=8080
  1. yml文件
1
2
server:
port: 8080
  1. yaml文件
1
2
server:
port: 8080

bean的获取

获取bean的方式有三种:

  1. 通过名称获取
1
2
3
4
5
6
@Autowired
private ApplicationContext applicationContext;

public void getBeanByName() {
applicationContext.getBean("beanName");
}
  1. 通过类型获取
1
2
3
4
5
6
@Autowired
private ApplicationContext applicationContext;

public void getBeanByType() {
applicationContext.getBean(BeanType.class);
}
  1. 通过名称和类型获取
1
2
3
4
5
6
@Autowired
private ApplicationContext applicationContext;

public void getBeanByNameAndType() {
applicationContext.getBean("beanName", BeanType.class);
}

bean的作用域

bean的作用域有五种:

  1. singleton (默认)

单例模式,一个容器只有一个实例。

  1. prototype (非单例)

原型模式,每次请求都会创建一个新的实例。

  1. request (web环境)

每次请求都会创建一个新的实例。

  1. session (web环境)

每次会话都会创建一个新的实例。

  1. application (web环境)

每次应用都会创建一个新的实例。

如何设置bean的作用域

通过注解

1
2
3
4
@Component  
@Scope("prototype")
public class PrototypeBean {
}

延迟初始化

懒汉模式

1
2
3
4
@Component
@Lazy
public class LazyBean {
}

启动时不会创建bean,第一次使用时才会创建。

第三方bean

springboot支持第三方bean的注入,只需要在配置类中添加@bean注解即可。

1
2
3
4
5
6
7
8
@Configuration
public class ThirdPartyBeanConfig {

@Bean
public ThirdPartyBean thirdPartyBean() {
return new ThirdPartyBean();
}
}

如何获取第三方bean:

1
2
3
4
5
6
@Autowired
private ApplicationContext applicationContext;

public void getThirdPartyBean() {
Object thirdPartyObject = applicationContext.getBean("thirdPartyBean"); // 可以通过方法名获取
}

@Componet 和 @Bean 的使用场景:

  1. @Component

项目中自定义的,使用@Component及其衍生注解,如@Service、@Repository、@Controller等。

  1. @Bean

项目中引入的第三方bean,使用@Bean注解。

springboot原理

springboot的核心是spring,springboot是对spring的封装,提供了一些便捷的功能。

起步依赖

通过maven的依赖传递实现的,可以通过spring-boot-starter-parent来管理版本。

1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
</parent>

自动配置

springboot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动配置,简化了开发。

自动配置方案

  1. @ComponentScan
1
2
3
4
5
6
7
@ComponentScan("com.example1", "com.example2")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@SpringBootApplication注解只能扫描当前包及其子包,如果需要扫描其他包,可以通过@ComponentScan注解,指定扫描其他包。

  1. @Import
  • 导入普通类
1
2
3
4
5
6
7
@Import(BeanObject.class)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
  • 导入配置类
1
2
3
4
5
6
7
@Import(BeanConfig.class)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
  • 导入ImportSelector接口实现类
1
2
3
4
5
6
7
@Import(BeanImportSelector.class)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1
2
3
4
5
6
public class BeanImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {BeanObject.class.getName()}; // or {"com.example.BeanObject"}
}
}
  • @EnableXxxx注解,封装了@Import注解 (更加方便)
1
2
3
4
5
6
// com.example.EnableSchedulingConfig
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(BeanImportSelector.class)
public @interface EnableScheduling {
}
1
2
3
4
5
6
public class BeanImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {BeanObject.class.getName()}; // or {"com.example.BeanObject"}
}
}
1
2
3
4
5
6
7
@EnableSchedulingConfig
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

自动配置原理

@SpringBootApplication注解由三个部分组成:

  1. @SpringBootConfiguration:标注当前类是一个配置类,继承自@Configuration。

  2. @ComponentScan:扫描当前包及其子包下的所有组件。

  3. @EnableAutoConfiguration:开启自动配置功能。(核心)

@EnableAutoConfiguration注解的原理:

  1. @Import(AutoConfigurationImportSelector.class):导入AutoConfigurationImportSelector类。

  2. AutoConfigurationImportSelector类的selectImports方法:

  • 获取所有的自动配置类
1
2
3
4
5
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), 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方法获取所有的自动配置类。

@Conditional注解

@Conditional注解是springboot提供的一个条件注解,用于判断是否满足某个条件,满足条件才会加载bean到IOC容器中。

  • @ConditionalOnMissingBean:当容器中没有指定的bean时,才会加载当前bean。

  • @ConditionalOnClass:当类路径下有指定的类时,才会加载当前bean。

  • @ConditionalOnProperty:当配置文件中有指定的属性时,才会加载当前bean。

1
2
3
4
5
@Bean
@ConditionalOnClass(name = "com.example.BeanObject2")
public BeanObject beanObject() { // 当环境中存在BeanObject2类时,才会加载当前bean
return new BeanObject();
}
1
2
3
4
5
@Bean
@ConditionalOnMissingBean(name = "com.example.BeanObject2") // 指定类型(value属性)或名称(name属性)
public BeanObject beanObject() { // 当环境中不存在BeanObject2类时,才会加载当前bean
return new BeanObject();
}
1
2
3
4
5
@Bean
@ConditionalOnProperty(name = "spring.datasource.url") // 当配置文件中存在spring.datasource.url属性时,才会加载当前bean
public BeanObject beanObject() {
return new BeanObject();
}