文章目录
控制反转(IOC)
1. 概念
1.1 问题引入
在之前的学习中,已经学会了使用三层架构开发程序,也就是web—>service—>dao,但是在调用的时候层与层之间存在着代码耦合.
1.2 解决思路
Spring解决上述问题的思路其实很简单,它改变了对象的创建者
传统方式:servlet需要service了,就是由Servlet主动创建
Spring方式:所有的对象都是由Spring框架提前创建出来,存储到一个容器中,servlet需要Service了,就向Spring要一个
1.3 IOC概念
IOC( 控制 反转 )是一种设计思想,它的目的是指导我们设计出更加松耦合的程序
控制:指的是对象创建权
反转:指的对象的创建由程序员在类中主动创建反转到由Spring容器来创建
2. 依赖及简单配置
2.1 pom文件依赖导入
pom代码:
<dependencies>
<!--spring核心-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
2.2 创建接口和实现类
//接口
public interface DeptDao {
// 保存
void save();
}
//实现类
//@Component 标注在类上 作用:当Spring扫描到这个注解之后,就会使用当前类创建对象,并将对象放入Spring容器中
//这个对象在容器中会有一个标识(id),默认是当前类名首字母小写(deptDaoImpl),也支持使用value属性自定义
//@Component(value = "deptDaoImpl") 只有一个value时可以省略
@Component("deptDaoImpl")
public class DeptDaoImpl implements DeptDao {
@Override
public void save() {
System.out.println("保存成功");
}
}
2.3 添加配置类
//这个用于Spring的核心配置类,就相当于原来的xml配置文件
@ComponentScan("com.cy")//组件扫描(注解扫描),它需要我们提供一个包命,只有在这个这个包(及其子包)下类中的注解才会被Spring扫描
public class SpringConfig {
}
2.4 测试
public class SpringTest {
@Test
public void test1(){
//1.读取配置类的信息,初始化Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//2.从容器中获取对象(使用对象的标识)
DeptDao deptDao = (DeptDao) context.getBean("deptDaoImpl");
deptDao.save();
}
}
3. 案例细节
3.1 Bean创建
向Spring中声明自己开发的类对象的注解,主要有下面四个
* @Component
用于实例化对象,它支持一个value属性类定义bean在容器中的唯一标识
如果不写,默认值为类名的首字母小写
* @Controller @Service @Repository
这三个注解的功能跟@Component类似,他们分别标注在不同的层上。
@Controller 标注在表示层的类上
@Service 标注在业务层的类上
@Repository 标注在持久层的类上
推荐使用这三个,当一个类实在不好归属在这三个层上时,再使用@Component
3.2 Bean作用域
在类上使用@Scope注解定义Bean的作用域,Spring支持如下五种作用域,我们目前常用的是第一种
- singleton 单例,对于一个类,只会创建一个对象,每次从容器中获取,拿到的都是这个对象
- prototype 多例,对于一个类,每次从容器中获取,都会创建一次,得到一个新的对象
- request 在web环境中,每个请求范围内会创建新的对象
- session 在web环境中,每个会话范围内会创建新的对象
- application 在web环境中,每个应用范围内会创建新的对象
① 单例对象 - singleton
对于一个类来说,只会创建一个对象,每次从容器中获取,拿到的都是这个对象
② 多例对象- prototype
对于一个类,每次从容器中获取都会创建一次,得到一个新的对象
//测试对象的单例和多例
@Test
public void test2(){
//1.读取配置类的信息,初始化Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//2.从容器中获取两次对象(使用对象的标识)
DeptDao deptDao1 = (DeptDao) context.getBean("deptDaoImpl");
DeptDao deptDao2 = (DeptDao) context.getBean("deptDaoImpl");
System.out.println(deptDao1 == deptDao2)//单例:true 多例:false;
}
3.3 Bean的创建时间
① 单例对象
默认情况下,单例对象会在容器创建时就创建;也可以使用@Lazy将创建时机延迟到第一次获取的时候创建
② 多例对象
多例对象会在每次获取的时候才创建
3.4 Bean获取
Spring容器启动时,会把其中的bean都创建好,如果想要主动获取这些 bean,可以使用容器getBean()方法
- getBean("id") 使用bean的id从容器中查找对象
- getBean(Bean.class) 使用bean的class类型从容器中查找对象
- getBean("id",Bean.class) 使用bean的id和class类型从容器中查找对象
- 如果查找的id在容器中不存在,会报错
NoSuchBeanDefinitionException: No bean named ‘deptDaoImpl1’ available- 如果查找的类型在容器中不存在,会报错
NoSuchBeanDefinitionException: No qualifying bean of type ‘DeptDao’ available- 如果查找的类型在容器中存在多个,会报错
NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.cy.dao.DeptDao’
available: expected single matching bean but found 2: deptDaoImpl,deptDaoImpl2