目录
1.7面试题1:Spring容器的bean是单例的还是多例的?单例的bean是什么时候实例化的?
2.3什么时候使用@Component声明bean,什么时候使用@Bean注解?
1.Bean的作用域
1.1bean作用域
- Spring支持五种作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内同名称的bean只有一个实例(单例)(默认) |
prototype | 每次使用该bean时会创建新的实例(非单例/多例) |
request | 每个请求范围内会创建新的实例(web环境中,了解) |
session | 每个会话范围内会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的实例(web环境中,了解) |
1.2注意:
默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)。
1.3示例代码
@Scope("prototype")
@RequestMapping("/depts")
@RestController
public class DeptController {
}
1.4单例的bean(singleton)
@Sl4j
@RestController
@Scope("singleton")
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/depts")
public Result list() {
log.info("查询全部部门数据");
List<Dept> deptList = deptService.findAll();
return Result.success(deptList);
}
}
- 无状态的bean
- 节约资源、提升性能
1.5多例的bean(prototype)
@Scope("prototype")
@Component
public class DataProcessor {
private List<EmpModel> dataList = new ArrayList<EmpModel>(); // 暂存数据
private Integer errCount = 0; // 错误数据统计
@Autowired
private EmpMapper empMapper;
public void process(List<Emp> empList) {
dataList = empList.stream().map(emp -> {
// 数据处理
}).toList();
}
public void handle() {
// ...
}
}
- 有状态的bean
1.6注意:
实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
1.7面试题1:Spring容器的bean是单例的还是多例的?单例的bean是什么时候实例化的?
- 默认是单例的
- 单例的bean,默认是项目启动时实例化的(通过@Lazy可以延迟初始化)
1.8面试题2:Spring容器的bean是线程安全的吗?
- bean的线程安全取决于bean的状态及bean的作用域
- 单例bean:如果是无状态的bean,内部不保存任何状态信息,则是线程安全的。
- 单例bean:如果是有状态的bean,内部会保存状态信息,多个线程会同时操作该bean时,可能会出现数据不一致的问题,这样的bean则是线程不安全的。
1.9延迟到第一次使用的时候,再来创建这个Bean
默认bean是单例的 - singleton
- 默认单例的bean是在项目启动时创建的,创建完毕后,会将该bean存入IOC容器。
//@Lazy //延迟初始化 ----> 延迟到第一次使用的时候,再来创建这个bean
@Scope("prototype") //非单例的 / 多例的
@RestController
public class DeptController {
public DeptController() {
System.out.println("创建DeptController对象...");
}
}
注释解释
@Lazy
:延迟初始化注解。如果加上这个注解,bean会在第一次被使用时才进行创建,而不是在项目启动时就创建。@Scope("prototype")
:指定bean的作用域为多例(prototype),即每次请求都会创建一个新的实例。
2.第三方Bean
- 如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解。
- 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类。
2.1示例代码
2.1.1启动类(不推荐)
@SpringBootApplication
public class SpringbootWebConfigApplication {
@Bean // 将方法返回值交给IOC容器管理,成为IOC容器的bean对象
public AliyunOSSOperator aliyunOSSOperator(AliyunOSSProperties ossProperties) {
return new AliyunOSSOperator(ossProperties);
}
}
2.1.2配置类(推荐)
@Configuration
public class OSSConfig {
@Bean
public AliyunOSSOperator aliyunOSSOperator(AliyunOSSProperties ossProperties) {
return new AliyunOSSOperator(ossProperties);
}
}
2.2注意:
- 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
- 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
2.3什么时候使用@Component声明bean,什么时候使用@Bean注解?
- 一般如果是项目中自定义的类,使用@Component及其衍生注解(如@Service、@Repository、@Controller等)。
- 如果是引入第三方依赖中的类,使用@Bean注解。