IoC简介
IoC(Inversion of Control)控制反转,是一种设计原则。一般情况创建一个对象我们都会通过new关键字来操作,而IoC顾名思义由代码(也就是IoC容器)来控制对象的创建。
简单的说:通过使用IoC可以将对象的死活交给容器,由容器负责。
能做什么?
首先需要明确,IoC是一种设计原则,一种思想,通过这种原则设计可以让我们码出松耦合、优良的程序。
IoC容器
Spring IoC容器是一个管理Bean的容器,在Spring的定义中,它要求所有IoC容器都实现BeanFactory接口。
装配Bean到容器
Spring可以通过XML和java配置文件装配Bean,不过SpringBoot推荐使用注解的方式来装配Bean。
简单使用
一个简单的javabean
- @Configuration 注解说明这是java的一个配置文件,spring的容器根据它来生成IoC容器去装配Bean。
- @Bean 代表将initUser方法返回的POJO装配到IoC容器中,属性name就是bean的名称
public class User {
private String name;
/** setter and getter **/
}
一个用于配置bean信息的类
@Configuration
public class Appconfig {
@Bean(name = "user")
public User initUser(){
User user = new User();
return user;
}
@Bean(name="people")
public People initPeople(){
People people=new People();
return people;
}
}
使用bean
- 使用AnnotationConfigApplicationContext来构建自己的IoC容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(Appconfig.class);
User user =ctx.getBean(User.class);
People people=ctx.getBean(People.class);
通过扫描装配Bean
创建一个可被扫描的javabean
- @Component表明这个类会被IoC容器扫描装配 people就是该bean的名称
- @Value是指定具体的值
@Component("people")
public class People {
@Value("1")
private Long id;
@Value("name")
private String Name;
}
配置类
- @ComponentScan 它会扫描使用@Component注解的类
- 但是注意@ComponentScan只会扫描它所在的包和其子包,其他路径的包是扫描不到的
- 如果要扫描其他包可以为@ComponentScan指定basePackages
- @ComponentScan使用详细总结(这里超链接)
@Configuration
@ComponentScan
public class Appconfig {
}
使用bean
和之前并没有什么区别
ApplicationContext ctx = new AnnotationConfigApplicationContext(Appconfig.class);
User user =ctx.getBean(User.class);
People people=ctx.getBean(People.class);
使用第三方Bean
@Configuration
public class Appconfig {
@Bean(name = "user")
public User initUser(){
User user = new User();
return user;
}
}
通过以上简单使用的Demo不难理解,装配一个Bean其实就是用@Bean注解定义一个返回该类型对象的函数,因此在使用第三方Bean的时候将User换成导入的第三方类即可。
IoC实现方式
IoC有两种实现方式:依赖注入和依赖查找。两者的区别在于,前者是被动的接收对象,在类A的实例创建过程中即创建了依赖的B对象,通过类型或名称来判断将不同的对象注入到不同的属性中,而后者是主动索取相应类型的对象,获得依赖对象的时间也可以在代码中自由控制。
依赖注入
- 基于接口。实现特定接口以供外部容器注入所依赖类型的对象。
- 基于 set 方法。实现特定属性的public set方法,来让外部容器调用传入所依赖类型的对象。
- 基于构造函数。实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。
- 基于注解。基于Java的注解功能,在私有变量前加“@Autowired”等注解,不需要显式的定义以上三种代码,便可以让外部容器传入对应的对象。该方案相当于定义了public的set方法,但是因为没有真正的set方法,从而不会为了实现依赖注入导致暴露了不该暴露的接口
在Springboot中依赖注入主要是基于注解来实现的
相关注解
- @Autowired自动注入 可以和**@Qualifiler以及@Primary**配合使用来消除冲突
- @Resource指定名称注入
- @Service @Controller @Respository 用此注解标注的类相当于使用了@Component
实例
创建一个javabean
@Component
public class Test {
public void saySome(){
System.out.println("我是被注入进来的");
}
}
通过@Autowired注解使用该bean
@Autowired
private Test test;
没错就是这么简单,使用@Autowired即可自动注入该bean
生命周期
在某些情景中,需要自定义初始化或者销毁Bean的过程,来满足Bean特俗初始化和销毁的要求,比如来使用数据库的时候,希望在关闭的时候调用close方法来释放数据库的连接资源。
Bean的生命周期:
- Bean的定义
- Bean的初始化
- Bean的生存期
- Bean销毁
Bean的生命周期
在生命周期中进行操作
方法:在编写bean的时候需要实现特定接口的特定方法,这样spring会自动调用这些方法
比如:BeanNameAware、BeanFactoruAware、ApplicationContextAware、InitializingBea、DisposableBean
初始化和销毁的方法实现
同样是在bean中自定义一个方法 使用上**@PostConstruct 和 @PreDestory**注解
@Postconstruct
public void init(){
}
@PreDestory
public void destory(){
}
Bean的作用域
Spring有如下集中作用域
类型 | 范围 | 描述 |
---|---|---|
singleton | 所有spring应用 | 默认值 ioc中只存在单例 |
prototype | 所有spring应用 | IoC取出一个bean就创建一个bean |
session | spring web | Http会话 |
application | spring web | web工程生命周期 |
request | spring web | web单次请求 |
globalSession | spring web | 在一个全局的 HTTP Session 中, 一个 Bean 定义对应一个实例 。 实践 中基本不使用 |
修改作用域方法
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ScopeBean{
}