1、SpringIOC
Spring框架的两大核心之一
IOC控制反转,将对象创建权交由Spring去管理,我们需要使用某个对象时直接从Spring框架获取即可
之前创建对象的步骤
class A {}
class Test {
main;
A a = new A(); //由我们自己创建对象
}
Spring框架的对象的创建
对象不由我们创建,Spring框架已经帮我们创建好所有的对象,使用的时候直接Spring框架获取就可以使用
class B{}
class Test{
public static void main(String[] args) {
从Spring容器中获取B对象(注入,ApplicationContext......)
}
}
2、Spring显式和隐式的配置Bean
2.1 显式
-
使用两个注解配合使用@Configuration和@Bean
- 在项目中配置类,通过@Configuration在类上使用来标明该类是一个配置类
- 在配置类中使用@Bean注解标注的方法,返回一个对象,该对象由Spring容器管理
由@Bean注解的方法可以实现注入
@Configuration public class Test { @Bean // 在此处会获取容器中User对象并注入 public DataSource Test(User user) { return new DataSource(); } }
2.2 隐式
使用两个注解配来合使用@Component(及衍生注解)和@ComponentScan组件扫描
- 在项目中自己创建的类要加@Component注解(及组件类注解)标记该类组件
组件类注解:
- @Component 通用组件注解
- @Controller / @RestController 控制器组件
- @Service 业务层注解
- @Respository 持久化/数据层注解(连接数据库)
- @Configuration 配置类组件
-
在配置类上加@ComponentScan(“组件所在的包”)来进行配置
使用的时候:
- 自己创建的类,需要容器管理的时候,使用 隐式的 例如:UserController
- 已经写好的类,需要容器管理的回收,是有 显式的 例如:DataSource
-
Baen的ID是有不同的规则的:
- @Bean注解的方法,方法名称就是BeanID(可以在@Bean的注解指定BeanID)
- 组件扫描:跟类的名称有关 UserController (第一个首字母大写第二字母小写其他不管),Bean的ID就是userController(将首字母变为小写后面不变)除了这种情况之外其他的bean的ID就是类名,也可以在组件中指定branid
3、从Spring容器中获取Bean对象
-
ApplicationContext - 应用程序上下文对象
该对象代表Spring容器,会存在于整个项目生命周中,所以可以通过该对象获取Spring容器中所有Bean对象
-
如何获取到ApplicationContext对象
ApplicationContext context = SpringAapplication.run(配置类.class)
-
如何通过ApplicationContext对象来获取某个Bean对象 – 三种方式
- 更具类型
UserController userConteoller = context.getBean(UserController.class)
- 根据BeanID获取,默认返回是object类型,需要强转
UserController userController = (UserController) context.getBean("userController")
- 更具ID和类型来获取(最常用)
UserController userController = context.getBean("userController",UserController.class)
4、Bean的作用域
-
作用域是Bean的属性,可以单独对某个Bean的作用域进行修改
-
Spring容器配置Bean对象的时候,默认所有Bean对象都是单例
-
Spring容器中Bean的常见作用域
- singleton – 单例 Spring容器默认 在容器中仅有一份,使用的时候大家共用一份
- prototype – 原型 Spring容器中,每个获取Bean对象,都是重新实例化,使用起来每次都是新的
- request – 每个request对象代表一次请求,每发起一次请求,都会重新实例化用到的Bean对象
- session – 每次创建一个新的session对象,都会重新实例化用到的Bean对象
-
如何修改作用域
通过@Scope来定义
@Bean @Scope("prototype") public UserService user() { return new Uservice(); }
5、依赖注入 @Autowired和@Resource
该注解是由Spring框架提供的,默认会更具类型注入
-
三种注入方式:
- 构造注入:是Spring建议的,具有不变性(外部不可改变),可以大概率的避免NPE(构造的作用给成员变量赋值),如果该类只有一个构造方法,那么可以省略不写@Autowired也会注入,如果有多个就必须写了
- setter注入:不具有不变性(可以通过调用set方法来设置值,可以变化)
- 字段注入:会出现空指针(NPE,如果注入的对象某个属性没有赋值,会出现空指针异常)
-
@Autowired可能会产生歧义
如果容器中有多个类型相同但是ID不同的bean,使用@Autowired注入的时候会报错
如果想消除歧义:
- 使用@Autowired配合@Qualifier(“BeanID”)(缺一不可,不可用于setter注入和字段注入)
- 使用@Autowired配合属性名称,这时候@Autowired会自动匹配与属性名相同的BeanID的bean进行注入
-
@Resource 是JDK提供的注解,会先按照名称,如果名称不匹配,在按照类型
总结:@Autowired和@Resource在正常的项目中使用起来没有区别
-
6、Bean 的生命周期
-
初始化
-
加载Bean的定义
检查@Bean注解和组件类注解,将Bean的定义加载到BeanFactory中(ApplicationContext就是一个BeanFactory),在BeanFactroy中,Bean的ID和类型都被索引
后处理Bean的定义,调用BFPP,用于修改Bean定义的属性(比如作者用域),这个阶段结束后,Bean定义加载结束,即将开始实例化Bean
BFPP – BeanFactoryPostProcessor 可以自己定义实现该类接口(通常不建议)Spring帮我们几乎所有能做的事情
常见的有从属性文件,读取其中属性
PropertySourcePlaceholderConfigurer,实现了BFPP接口,用于读取属性
-
当构造注入(实例化)和setter注入之后,在初始化的前面和后面有一个接口BPP,BPP中有两个方法可以在初始化前和初始化进行操作
BPP – BeanPostProcessor
有两个生命周期注解:@PostConstruct和@PreDestory
-
@PostConstruct在Bean初始化的时候调用该注解标记的方法,在setter注入之后,初始化之前调用该注解标记的方法
-
@PreDestory在Bean正常销毁的时候会调用标记的方法(容器正常被关闭)
如果是@Bean标记的方法返回的Bean
想要在初始化和销毁的时候调用某个方法,需要配置属性
@Bean(initMethod = “initDemo”,destoryMethod = “dsDemo”)
r注入之后,初始化之前调用该注解标记的方法
-
@PreDestory在Bean正常销毁的时候会调用标记的方法(容器正常被关闭)
如果是@Bean标记的方法返回的Bean
想要在初始化和销毁的时候调用某个方法,需要配置属性
@Bean(initMethod = “initDemo”,destoryMethod = “dsDemo”)