Spring Boot
Spring Boot 配置文件
Spring Boot中支持 application.properties
、application.yaml
、application.yml
三种配置,推荐使用后两种(是同一种)。
server.port=8080
server:
port: 8080
三种配置文件的优先级 application.properties
> application.yml
> application.yaml
除了使用配置文件配置属性,还可以使用Java系统指令和命令行参数配置
Java系统属性
-Dserver.port=8081
命令行参数
--server.port=8082
分别对应:
优先级:命令行参数 > Java指令 > application.properties
> application.yml
> application.yaml
运行jar包时指定优先级:
java -Dserver.port=8081 -jar 项目名.jar --server.port=8082
要打包一个Spring Boot项目,需要引入 spring-boot-maven-plugin
插件
org.springframework.boot
spring-boot-maven-plugin
管理Bean
获取Bean
对于单例非延时加载的Bean而言,Spring Boot项目在启动时会自动创建IOC容器,并把Bean对象创建好放入IOC容器中。这样编写程序时我们只需要注入IOC容器中需要依赖的Bean对象即可。
Spring Boot获取Bean的三种方式
import com.zhw.UserController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
@SpringBootTest
public class SpringBootGetBeanTest {
@Autowired
private ApplicationContext applicationContext; // IOC容器对象
@Test
public void getBeanTest() {
// 根据Bean的名称获取 声明一个Bean没有指定名称,默认是首字母小写
UserController bean1 = (UserController) applicationContext.getBean("userController");
System.out.println("bean1 = " + bean1);
// 根据Bean的类型获取
UserController bean2 = applicationContext.getBean(UserController.class);
System.out.println("bean2 = " + bean2);
// 根据Bean的名称和类型获取
UserController bean3 = applicationContext.getBean("userController", UserController.class);
System.out.println("bean3 = " + bean3);
}
}
运行后结果为:
bean1 = com.zhw.UserController@3b8ec001
bean2 = com.zhw.UserController@3b8ec001
bean3 = com.zhw.UserController@3b8ec001
可以看出获取到的Bean对象都是同一个,也就是说 Spring Boot 的 Bean 默认是单例的
一般是直接@Autowired注入
Bean的作用域
在 Spring 框架中,有以下五种常用的作用域(Scope):
Singleton(单例作用域):
这是默认的作用域,也是最常见的作用域。在 Singleton 作用域下,Spring 容器中只会创建一个共享的实例对象,并在整个应用程序生命周期内都重用该对象。无论何时请求获取该 Bean,都会返回同一个实例。
Prototype(原型作用域):
在 Prototype 作用域下,每次请求获取 Bean 时,Spring 容器都会创建一个新的实例对象。这意味着每次获取该 Bean 都会得到一个不同的实例。
Request(请求作用域): — 了解即可
在 Request 作用域下,每个 HTTP 请求都会创建一个新的 Bean 实例。这对于 Web 应用程序非常有用,因为它确保了每个请求都拥有自己独立的 Bean 实例,以避免并发问题。
Session(会话作用域): — 了解即可
在 Session 作用域下,每个用户会话(通常是一个 Web 会话)都会创建一个新的 Bean 实例。这使得可以为每个用户维护一个独立的状态,通常用于 Web 应用程序中。
GlobalSession(全局会话作用域): — 了解即可
GlobalSession 作用域通常用于分布式环境,如基于 Spring 的 Portlet 应用程序。它类似于 Session 作用域,但在集群环境中可以共享。
@Component
@Scope("prototype")
public class MyPrototypeBean {
// ...
}
这里的
@Scope("prototype")
表示将该 Bean 的作用域设置为原型(Prototype)。这个类是默认单例的,在项目启动时就会将该类实例化放入IOC容器中。
@Lazy
@Lazy
@Component
@Scope("prototype")
public class MyPrototypeBean {
// ...
}
如果在类上加了@Lazy注解后,该类就会延迟初始化,会在第一次使用的时候加载。
第三方Bean
如果我们需要使用第三方Bean(无法声明@Component等注解加入IOC的类),就需要使用@Bean注解,将返回值加入IOC容器,这里以RedisTemplate为例
/**
* 第三方Bean
*/
@Slf4j
@Configuration
public class CommonConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
log.info("开始创建Redis模板对象......");
RedisTemplate redisTemplate = new RedisTemplate<>();
// 设置redis的连接工厂对象
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置redis key的序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
如果在声明第三方Bean时需要依赖注入,只需要将Bean对象作为方法形参传入即可。
例如上面redisTemplate方法的形参
redisTemplate(RedisConnectionFactory redisConnectionFactory)
Spring 容器会自动装配,根据该类型(RedisConnectionFactory)自动到IOC容器找到Bean对象并注入
Spring Boot原理
Spring所有的框架都基于Spring Framework,但是基于Spring Framework开发比较繁琐。因此Spring4.0后推出了Spring Boot来简化Spring框架的开发。它有两个非常强大的功能:起步依赖
和自动配置
起步依赖
起步依赖的原理就是 maven
的依赖传递。比如导入spring-boot-starter-web 依赖后会依赖传递包含其它好几个依赖。
自动配置
Spring Boot 会在Spring容器启动后,将一些配置类、Bean对象自动创建并存到IOC容器中去。这就是自动配置,可以不用我们自己去创建对象,大大的简化了开发。
例如项目中我只引入了AMQP(包含RabbitMQ)的依赖
org.springframework.boot
spring-boot-starter-amqp
并且在项目中并没有去做声明RabbitTemplate的操作,但是却能注入RabbitTemplate
/**
* Spring Boot 自动配置测试类
*/
@SpringBootTest
public class SpringBootAutoConfigurationTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void autoConfigurationTest() {
rabbitTemplate.convertAndSend("", "demo.simple", "Success!!");
}
}
@ComponentScan
启动类上的@SpringBootApplication就具有包扫描的功能,但是它的扫描范围是 当前包及其子包 ,扫描不到其他的包。因此如果我们需要扫描第三方包可以在启动类上加 @ComponentScan
注解。
使用 value
或者 basePackages
属性指定要扫描的包路径,默认是value
@ComponentScan({"com.demo", "com.test"})
但是使用这种方法去扫描包非常繁琐,并且一扫描就是一整个包,可能我们只是需要这个包下面的几个Bean呢?这样就会造成性能的浪费。
@Import(了解)
还可以使用@Import注解,将我们需要的单个Bean注入Spring的IOC容器,这样就不用扫描一整个包了。
导入普通类,即用 @Component
注解声明的类
@Component
public class Generate {
// ...
}
@Import({Generate.class}) // 导入普通类
导入配置类,用 @Configuration
注解声明的类。配置类中的所有Bean对象都会交由Spring的IOC管理
@Configuration
public class DemoConfig {
@Bean
public Product product() {
return new Product();
}
@Bean
public Consumer consumer() {
return new Consumer();
}
}
@Import({DemoConfig.class}) // 导入配置类
导入 ImportSelector
接口实现,返回的是一个String类型的数组,里面写类的全路径
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.demo.MyImportSelector"};
}
}
@Import({MyImportSelector.class}) // 导入 `ImportSelector` 接口实现
@Enablexxx(推荐使用)
看到这里就会想,之前导入的那些依赖也没有配置包扫描路径,是怎么拿到的?对于要使用哪些Bean,第三方依赖已经帮我们提供了 @Enablexxx
这样的注解指定要导入的Bean,它实际上就是封装了 @Import
注解。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({MyImportSelector.class})
public @interface EnableMyConfig {
}
@EnableMyConfig
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}