1. IOC底层的原理
1.1 什么是IOC
(1)Inversion of Control 控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理 (2)使用 IOC 目的:为了耦合度降低——》eg: 在user类中调用person类中的方法,首先需要在user类中创建person对象,通过person对象调用person类中的方法。 (3)做入门案例就是 IOC 实现。 |
---|
2.2 IOC的底层原理
(1) xml 解析、工厂模式、反射 |
---|
2.3 实现过程原理图
2. IOC解耦(BeanFactory)
2.1 IOC接口
2.1.1 IOC思想基于IOC容器完成,IOC容器底层就是beanFactory
2.1.2 Spring提供IOC容器实现的两种方式(2个接口):
实现原理是:
step1: 加载Spring配置文件;
step2: 获取配置文件中创建的实例。
- method1: ApplicationContext
- BeanFactory(工厂类)接口的子接口,功能更加强大。是面向开发人员使用的。
- 特点: 在加载配置文件时,在配置文件中就会创建对象。——》优点:服务器启动时就创建对象,而不是在操作时才执行
- method 2: BeanFactory
- 是spring中内置使用的接口,不提供给开发人员使用。(不建议用)
- 特点:
- 加载配置文件的时候,不会创建对象。只有在获取对象的时候,才会创建对象。
public class testDemo {
/** 测试spring创建对象的过程*/
@Test
public void testAdd() {
// step1: 加载spring的配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
// step2: 获取配置所创建的对象
User user = context.getBean("user", User.class); // 括号中user是id的值,User.class表示把对象转换成User类对象
System.out.println(user); // 输出user对象
user.add(); // user对象调用方法
}
}
2.1.4 ApplicationContext实现类
- 加载配置文件的时候,不会创建对象。只有在获取对象的时候,才会创建对象。
- (1)中需要写的是:配置文件在盘中的路径: c://
- (2)中需要写的是:在当前项目中的相对路径
3. IOC操作-Bean管理1(基于xml)
3.1 什么是Bean管理?
| Bean 管理指的是两个操作:
(1) Spring 创建对象
(2) Spring 注入属性—->类中有属性。传统的方法是通过类中的set()来给属性设置值。现在这个步骤也交给spring来管理。 | | —- |
3.2 Bean管理操作有2种方式
(1)基于 xml 配置文件方式实现 (2)基于注解方式实现 |
---|
3.3 基于xml方式创建对象
使用bean标签,添加对应的属性:
——-》执行无参构造方法完成对象的创建。
<!--配置User对象的创建:-->
<!-- id: 对象的表示-->
<!-- class:所要创建的类的全路径(包和类的路径)-->
<!-- name: (了解) 和id的作用一致。 id中不能加/,name中可以加特殊符号。-->
<bean id="user" class="com.atguigu.spring5.User"></bean>
3.4 基于xml方式注入属性
3.4.1 DI
DI: 依赖注入。——》就是注入属性。在创建对象的基础之上执行。
2种实现方式:
- method1: 通过类中的属性的set()和xml中的properties属性
- method2: 通过有参构造
3.4.2 多种实现方式
3.4.2.1 基于set()实现
step1: 编写类及属性、属性的set() 方法 step2: xml文件配置 step3: test |
---|
<!-- step1: 注入类及对象 -->
<bean id="book" class="com.atguigu.spring5.Book">
<!-- step2: 注入属性-->
<property name="bAuthor" value="神雕侠侣"></property>
<property name="bName" value="金庸"></property>
</bean>
/** */
@Test
public void testBook() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
2.4.2.2 基于有参构造函数实现
<bean id="order" class="com.atguigu.spring5.Orders">
<constructor-arg index="0" value="book的订单"/>
<constructor-arg index="1" value="京东"/>
</bean>
3.5 基于xml注入其他类型属性
3.5.1 基本概念
字面量:给属性设置固定值,这个固定值就是字面量。
字面量可以是空值null:
<!-- step1: 注入类及对象 --> <bean id="book" class="com.atguigu.spring5.Book"> <!-- step2: 注入属性--> <!-- 设置一个空值--> <property name="bAuthor"> <null/> </property> </bean>
字面量中包含特殊符号:
<!-- step1: 注入类及对象 --> <bean id="book" class="com.atguigu.spring5.Book"> <!-- step2: 注入属性--> <!-- 设置值中含有特殊符号--> <!-- 方法一:<> 进行转义--> <!-- 方法二:CDATA--> <property name="bAuthor"> <value> <![CDATA[<<南京!南京!>>]]> </value> </property> </bean>
3.5.2 注入属性—外部bean
| web层调用service层, service层调用dao层。
note:
dao: data access object | | —- |
(1)创建2个类,service类和dao类;
(2) 在service增加dao类作为属性,添加set();
(3)在spring配置文件中进行配置——property标签
<!-- step1: 创建dao和service对象-->
<bean id="service" class="com.atguigu.spring5.service.UserService">
<!-- step2: 在service中注入dao: name: 类中的属性名称, ref指向所创建的dao对象id-->
<property name="userDao" ref="dao"></property>
</bean>
<bean id="dao" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
(4) 测试
public class TestBean {
/** */
@Test
public void testBean() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
UserService service = context.getBean("service", UserService.class);
service.add();
}
}
3.5.3 注入属性—内部bean和级联赋值
析: 类A当作类B 的一个属性;
(1) 一对多关系: 部门-员工; 一个部门有多个员工,一个员工属于一个部门。
(2) 在实体类之间表示一对多关系:
public class employee {
private String eName;
private String eGender;
// 员工属于某一个部门
private Department dept;
public void seteName(String eName) {
this.eName = eName;
}
public void seteGender(String eGender) {
this.eGender = eGender;
}
public void setDept(Department dept) {
this.dept = dept;
}
}
(3) xml中配置属性
== 注意 属性dept的级联赋值;
<!-- step1: 内部bean-->
<bean id="emp" class="com.atguigu.spring5.bean.employee">
<!-- step2: 普通的内部属性-->
<property name="eGender" value="female"></property>
<property name="eName" value="lucy"></property>
<!-- step2: 外部bean属性-->
<property name="dept">
<bean id="innerDept" class="com.atguigu.spring5.bean.Department">
<property name="dName" value="保安部"></property>
</bean>
</property>
</bean>
3.6 xml注入集合属性
3.6.1 注入一个array类型属性
3.6.2 注入一个List集合类型的属性
3.6.3 注入Map集合类型属性
step1: 创建student类,并在类中设置各种数据类型的值;
public class Student {
// 数组类型的属性
private String[] courses;
// 创建list类型的数组
private List<String> list;
// set类型的属性
private Set<String> set;
// map类型的属性
private Map<String,String> maps;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSet(Set<String> set) {
this.set = set;
}
@Override
public String toString() {
return "Student{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", set=" + set +
", maps=" + maps +
'}';
}
public void test(){
System.out.println(Arrays.toString(courses));
System.out.println(list);
System.out.println(maps.entrySet());
}
}
step2: 在xml中注入属性值
<bean id="stu" class="com.atguigu.spring5.collectionType.Student">
<property name="courses">
<array>
<value>java课程</value>
<value>MySQL课程</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>三哥</value>
</list>
</property>
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<property name="set">
<set>
<value>李四</value>
<value>王麻子</value>
</set>
</property>
</bean>
3.6.4 如何在集合中设置 对象类型 的值?
析: 对象只能引用!
<!-- 在List集合中注入Course类型的值-->
<bean id="std" class="com.atguigu.spring5.collectionType.Stu">
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<!-- 创建多个course对象-->
<bean id="course1" class="com.atguigu.spring5.collectionType.Course">
<property name="cName" value="Spring5框架"></property>
</bean>
<bean id="course2" class="com.atguigu.spring5.collectionType.Course">
<property name="cName" value="MyBatis框架"></property>
</bean>
3.6.5 如何把集合注入的部分提取出来?让其作为公共的部分
step1: 在配置文件中引入util名称空间
xmlns:util="http://www.springframework.org/schema/util"
step2: 使用util标签完成List集合属性注入
<!-- step1: 提取list集合-->
<util:list id="stuList">
<value>易经经</value>
<value>九阳真经</value>
<value>乾坤大挪移</value>
</util:list>
<!-- step2: list的注入-->
<bean id="stu" class="com.atguigu.spring5.collectionType.Stu">
<property name="courseList" ref="stuList"></property>
</bean>
4. IOC操作-Bean管理2(基于FactoryBean)
4.1 bean概念梳理
Spring中有2种bean: 一种是普通bean, 一种是factoryBean
4.1.1 普通bean
通过xml文件中bean标签创建bean. 实例名就是id。 此时xml中定义的class类型就是返回的实例类型。
4.1.2 FactoryBean
4.2 FactoryBean的实现过程
析: 实质是半手动创建bean的过程。
原因: 在工厂bean中是手动创建对象,而工厂bean的实例则是由xml文件创建的。
4.2.1 step1: 创建类,让这个类作为FactoryBean, 实现接口FactoryBean
4.2.2 step2: 实现接口里的方法,在现实的方法中定义返回的bean类型
具体实现:
1. 类的编写:
定义的是MyBean类,返回的是Course类。
/*
* 在MyBean中创建Couse的对象
*/
public class MyBean implements FactoryBean<Course> {
/**
* 返回 couse对象
* @return
* @throws Exception
*/
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setcName("spring");
return course;
}
}
xml文件的配置:
<bean id="myBean" class="com.atguigu.spring5.factoryBean.MyBean"></bean>
test:
@Test public void test3(){ ApplicationContext context= new ClassPathXmlApplicationContext("bean3.xml"); Course course = context.getBean("myBean", Course.class); System.out.println(course); }
5. Bean管理(作用域)
5.1 单实例/多实例
在spring里可以设置是单实例还是多实例;
在默认情况下,bean是单实例对象;5.2 如何设置单实例还是多实例?
在spring配置文件里,bean标签里的 scope=”prototype” 代表多实例。
<bean id="myBean" class="com.atguigu.spring5.factoryBean.MyBean" scope="prototype"></bean> // prototype: 原型
5.3 singleton和prototype区别
singleton单实例,prototype多实例;
- 设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,而是在getBean() 时创建多实例对象。
6. Bean管理(生命周期)
6.1 什么是生命周期?
6.2 bean的生命周期
- 创建bean实例:通过无参/有参构造器创建
- 为bean的属性设置值和对其他bean引用(set( ))
- 调用bean初始化的方法:需要配置
- bean可以使用了
- 当容器在关闭的时候,会调用bean销毁的方法: 需要配置
7. IOC操作-Bean管理(xml自动装配)
7.1 自动装配
手动装配:给bean配置属性和属性值;
自动装配:根据指定装配规则(属性名称或者属性类型),Spring会自动将匹配得属性值进行注入。
7.2 演示自动装配过程
7.2.1 method1: 根据属性名称自动注入
<!-- 实现自动装配-->
<!-- 根据属性名称实现自动装配-->
<bean id="emp" class="com.atguigu.spring5.autoWire.Emp" autowire="byName">
</bean>
<bean id="dep" class="com.atguigu.spring5.autoWire.Dep"></bean>
7.2.2 method2: 根据属性类型自动注入
<!-- 实现自动装配-->
<!-- 属性类型-->
<bean id="emp" class="com.atguigu.spring5.autoWire.Emp" autowire="byType">
</bean>
<bean id="dep" class="com.atguigu.spring5.autoWire.Dep"></bean>
8. IOC操作-Bean管理(外部属性文件)
8.1 实现步骤
8.1.1 配置数据库信息
- 配置德鲁伊连接池
- 引入德鲁伊连接池依赖的jar包
| 资源池对象:
驱动;
url
user
passwd | | —- |
8.1.2 引入外部属性文件配置数据库连接池
创建外部属性文件,properties格式文件,写数据库信息
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/userDb prop.userName=root prop.password=root
把外部properties属性文件引入到spring配置文件中。
step1: 首先要引入context名称空间;
step2: 在spring配置文件使用标签引入外部属性文件。
<!-- 外部属性文件的引入-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
9. IOC操作-Bean管理(基于注解方式)
9.1 什么是注解
- 注解是代码中特殊的标记, 格式:@注解名称(属性名称1=属性值1,属性名称2=属性值2…)
- 注解可以用在类上、属性上、方法上
- 使用注解的目的:简化xml配置。
9.2 Spring针对Bean管理中创建对象提供的注解
- @Component
- 普通的注解
- @Service
- 业务逻辑层上
- @Controller
- web层
- @repository
- dao层
9.3 基于注解方式实现对象创建
9.3.1 step1: 引入依赖
9.3.2 step2: 开启组件扫描
告诉Spring,在哪些类上会使用注解。让Spring去扫描这些类。
- 引入context名称空间
xmlns:context=”http://www.springframework.org/schema/context“
指定需要开启组件扫描的包目录:
<context:component-scan base-package="com.atguigu.spring5"> </context:component-scan>
创建类,通过注解创建对象
// 注解中value="" 可以不写 // 不写时,默认值是类名的首字母小写 @Component(value = "userService") // 此写法等同于在xml中注入bean: <bean id="" class="" public class UserService { public void add() { System.out.println("service add....."); } }
测试
public class TestDemo { /** */ @Test public void testService() { ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); } }
9.4 基于注解的方式实现属性注入
9.4.1 Spring提供了哪些注解
@AutoWired
- 根据属性类型进行注入
- step1: 把service和dao类上添加创建对象的注解;
- step2: 在service中创建dao类型的属性。使用@Autowired进行注解。
// 定义Dao类型的属性, 不需要添加set方法,添加注入属性注解 @Autowired private UserDao userDaoImp;
@Qualifier
- 根据属性名称进行注入,要和autowired一起使用。
// 定义Dao类型的属性, 不需要添加set方法,添加注入属性注解 @Autowired @Qualifier(value = "userDaoImp1") // 避免多个接口实现类对象间的混淆 private UserDao userDaoImp;
- 根据属性名称进行注入,要和autowired一起使用。
@Resource
- 既可以根据类型又可以根据名称进行注入
- 是javax包中的,不是Spring中的
- 不建议使用 ```java @Resource //根据类型进行注入 private UserDao userDaoImp;
@Resource(name = “userDaoImp1”) // 根据名字进行注入 private UserDao userDaoImp;
4. @Value
1. 注入普通类型属性
```java
@Value(value = "abc") // 把值“abc”注入到属性中
private String name;
10. 纯注解开发
10.1 step1: 创建配置类,替代xml配置文件
需要使用@Configration 和 @ComponentScan(basePackages={“包的目录”})
@Configuration // 把当前类作为配置类
@ComponentScan(basePackages = {"com.atguigu"}) // 开始组件扫描
public class SpringConfig {
}
10.2 step2: 编写类和属性,以及注入
10.3 step3: 测试
注意:加载配置类的方法: AnnotationConfigApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();