1. Spring框架
1.1. Spring框架的作用
(1)Spring框架主要解决了创建对象和管理对象的相关问题。
(2)通过Spring创建并管理对象,可以使得开发者不再反复关心对象的创建过程,并且,默认情况下,由Spring创建的对象都是单例的,这是非常有必要的!
(3)由Spring创建的对象通常称之为Spring Bean。
由于Spring会创建并管理很多对象,所以Spring也通常被称之为Spring容器。
1.2. Spring框架的依赖项
Spring框架的基础依赖项是:spring-context。
1.3. 使用Spring框架创建对象
1.3.1. 组件扫描
(1)在配置类上,添加@ComponentScan注解可以开启组件扫描。
在Spring Boot项目中,启用类上的@SpringBootApplication注解中包含@ComponentScan。
关于@SpringBootApplication注解:
@SpringBootApplication
-- @ComponentScan
-- @SpringBootConfiguration
-- -- @Configuration
另外,如果没有在@ComponentScan上配置扫描的包,默认扫描的是当前配置类所在的包。
(2)在类上添加@Component或基于@Component的组合注解,即可将类标记为组件类。
在Spring框架中,组件注解有:
@Component:添加在类上,标记当前类是组件类,可以通过参数配置Spring Bean名称。
@Controller:添加在类上,标记当前类是控制器组件类,用法同@Component。
@Service:添加在类上,标记当前类是业务逻辑组件类,用法同@Component。
@Repository:添加在类上,标记当前类是数据访问组件类,用法同@Component。
@Configuration:添加在类上,仅添加此注解的类才被视为配置类,通常不配置注解参数。
在Spring MVC框架中,还新增了组件注解:
@RestController:添加在类上,标记此类是一个“响应正文”的控制器类。
@ControllerAdvice:添加在类上,标记此类中特定的方法将作用于每次处理请求的过程中。
@RestControllerAdvice:添加在类上,是@ControllerAdvice和@ResponseBody的组合注解。
Spring框架在执行组件扫描时,会扫描所配置的包及其子孙包,并尝试创建所有组件类的对象。
这种做法只适用于自定义的类。
1.3.2. @Bean方法
(1)在配置类中,可以自行设计方法,返回所需的对象,并在方法上添加`@Bean`注解,则Spring会自动调用此方法,并管理此方法返回的对象。
@Configuration
public class BeanConfiguration {
@Bean
public UserController userController() {
return new UserController();
}
}
这种做法适用于所有类型创建对象,但一般用于创建非自定义类的对象。
1.4. Spring Bean的作用域
(1)默认情况下,被Spring管理的对象都是单例的,也可以通过@Scope("prototype")修改为非单例的(相当于局部变量)。
(2)被Spring管理的单例的Spring Bean,默认情况下,都是预加载的(相当于饿汉式的单例模式),也可以通过@Lazy注解修改为懒加载的(相当于懒汉式的单例模式)。
注意:不要把Spring和单例模式这种设计模式直接划等号,只是Spring管理的对象的特征与单例模式的相同而已。
如果使用组件扫描的方式创建对象,则在类上添加`@Scope`或`@Lazy`来配置作用域,如果使用`@Bean`方法的方式创建对象,则在方法上添加这些注解来配置作用域。
1.5. Spring Bean的生命周期
仅当Spring Bean是单例的,才有必要讨论生命周期问题。
(1)在自定义的组件类中,可以自定义方法,并在方法添加@PostConstruct和@PreDestroy注解,将方法标记为初始化方法和销毁方法。
(2)在使用@Bean方法的情况下,可以在@Bean注解上配置initMethod和destroyMethod属性,来指定初始化方法和销毁方法的名称。
(3)初始化方法会在创建对象、完成自动装配之后,被Spring框架自动调用。
(4)销毁方法会在Spring框架销毁对象的前一刻被自动调用。
1.6. 自动装配
(1)自动装配:当某个属性,或某个被Spring自动调用的方法的参数需要值时,Spring会自动从容器中找到合适的值,为属性或参数注入值。
示例:为属性注入值
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
}
示例:为方法的参数注入值
@RestController
public class UserController {
private UserMapper userMapper;
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 自动装配
public UserController(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
(2)如果类中仅有1个构造方法,不需要添加`@Autowired`注解;如果类中有多个构造方法,Spring会尝试调用无参数的构造方法,如果某个构造方法添加了`@Autowired`注解,则必然调用添加了注解的构造方法。
@RestController
public class UserController {
private UserMapper userMapper;
@Autowired
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 自动装配
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
@Configuration
public class BeanConfiguration {
@Bean
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 自动装配
public UserController userController(UserMapper userMapper) {
UserController userController = new UserController();
userController.setUserMapper(userMapper);
return userController;
}
}
除此以外,通过@Value注解也适用以上做法!
(3)使用@Resource注解也可以实现自动装配,但是,它不可以添加在构造方法上!并且,它是javax包下的注解!从装配机制上,@Resource是先根据名称装配,再根据类型装配,而@Autowired是先根据类型进行查找,当冲突时再尝试根据名称装配。
(4)关于@Autowired的装配机制,它是先根据类型查找匹配类型的Spring Bean的数量,然后:
0个:取决于`@Autowired`注解的`required`属性的值
true(默认):装配失败,加载Spring时抛出`NoSuchBeanDefinitionException`异常。
false:放弃装配,但是,后续可能出现NPE(空指针异常)。
1个:直接装配,且成功
多个:将尝试根据名称进行装配:
存在名称匹配的:装配成功
不存在名称匹配的:装配失败,加载Spring时抛NoUniqueBeanDefinitionException异常。
另外,关于名称匹配:
Spring Bean的名称与属性(或参数)的名称相同
属性(或参数)的名称与Spring Bean的名称相同
通过`@Resource`的`name`属性指定Spring Bean的名称;通过`@Qulifier`注解指定Spring Bean的名称,结合`@Autowired`的机制一起使用
1.7. 概念
(1)IOC(Inversion of Control):控制反转,指的是将对象的创建、管理等控制权交给了框架
(2)DI(Dependency Injection):依赖注入,为对象的依赖项(类中的属性)注入值
Spring框架通过DI完善了IoC。