控制反转
1.1 IoC介绍
IoC (Inverse of Control)控制反转,将原本由我们手动完成的创建对象的工作交由Spring对象工厂来完成
1.2 Spring对象工厂使用
创建Bean
public class Book {
private int bookId;
private String bookName;
}
配置Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--通过bean标签将实体类 配置给 spring管理,id是当前实体类在Spring容器中的唯一标识 -->
<bean id="book" class="com.qfedu.entity.Book"></bean>
</beans>
获取Bean
//a.加载spring配置文件
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
//b.从Spring对象工厂获取对象
Book book = (Book)context.getBean("book");
1.3 DI(Dependency Injection) 依赖注入
★ set方法注入 :
使用property标签完成属性注入依赖于类中属性的set方法——set注入
1.3.1 依赖注入概念
Spring对象工厂完成对象创建的同时,为对象的属性赋值,称之为依赖注入。
- 在配置文件指定bean的属性值
- 通过对象工厂创建对象时,就会将指定的值注入
1.3.2 简单类型和字符串类型属性注入
public class Book {
private int bookId;
private String bookName;
}
<bean id="book" class="com.qfedu.entity.Book">
<!--
property标签,用于给创建的实例输入配置注入的值
name 属性 指定对象的属性名
value 属性 指定对象当前属性的值
-->
<property name="bookId" value="1001"/>
<property name="bookName" value="Java程序设计"/>
</bean>
1.3.3 日期类型
public class Book {
private int bookId;
private String bookName;
private Date bookTime;
}
- 方式1:
<bean id="book" class="com.qfedu.entity.Book">
<property name="bookId" value="1001"/>
<property name="bookName" value="Java程序设计"/>
<property name="bookTime" value="2020/07/29"/>
</bean>
- 方式2:
<bean id="time" class="java.util.Date"/>
<bean id="book" class="com.qfedu.entity.Book">
<property name="bookId" value="1001"/>
<property name="bookName" value="Java程序设计"/>
<property name="bookTime" ref="time"/>
</bean>
- 方式3
<bean id="book" class="com.qfedu.entity.Book">
<property name="bookId" value="1001"/>
<property name="bookName" value="Java程序设计"/>
<property name="bookTime" >
<bean class="java.util.Date"/>
</property>
</bean>
1.3.4 自建类型(自定义类类型)
public class Type {
private int typeId;
private String typeName;
}
public class Book {
private int bookId;
private String bookName;
private Type type;
}
- 方式1:
<bean id="book" class="com.qfedu.entity.Book">
<property name="bookId" value="1"/>
<property name="bookName" value="Java程序设计"/>
<!--自定义类类型的属性-->
<!--<property name="type" ref="type1"/>-->
<property name="type">
<bean class="com.qfedu.entity.Type">
<property name="typeId" value="10003"/>
<property name="typeName" value="地理"/>
</bean>
</property>
</bean>
- 方式2:
<bean id="type1" class="com.qfedu.entity.Type">
<property name="typeId" value="10001"/>
<property name="typeName" value="IT"/>
</bean>
<bean id="book" class="com.qfedu.entity.Book">
<property name="bookId" value="1"/>
<property name="bookName" value="Java程序设计"/>
<!--自定义类类型的属性-->
<property name="type" ref="type1"/>
</bean>
1.3.5 集合类型
- 单值集合(List\Set\数组)
public class Book {
private List<String> marks;
private Set<String> attrs1;
private String[] attrs2;
}
<bean id="book" class="com.qfedu.entity.Book">
<property name="marks">
<list>
<value>aa</value>
<value>bb</value>
<value>cc</value>
</list>
</property>
<property name="attrs1">
<set>
<value>aa</value>
<value>bb</value>
<value>aa</value>
</set>
</property>
<property name="attrs2">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</array>
</property>
</bean>
- 键值对集合(Map、Properties)
public class Book {
private Map<String,Object> attrs3;
private Properties attrs4;
}
<bean id="book" class="com.qfedu.entity.Book">
<!--map-->
<property name="attrs3">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value-ref="date"/>
</map>
</property>
<!--properties -->
<property name="attrs4">
<props>
<prop key="k1">v1</prop>
<prop key="k2">v3</prop>
</props>
</property>
</bean>
★ 构造器注入
如果类中没有set方法则不能使用property标签完成属性的注入,此时我们可以通过有参构造器完成注入
public class Type {
private int typeId;
private String typeName;
public Type() {
}
public Type(int typeId, String typeName) {
this.typeId = typeId;
this.typeName = typeName;
}
}
<bean id="type1" class="com.qfedu.entity.Type">
<!--
constructor-arg 指定构造器参数
index属性指定构造器参数的索引
value属性指定构造器参数的值
ref属性,当构造器参数是对象类型时,用于指定对象
-->
<constructor-arg index="0" value="10001"/>
<constructor-arg index="1" value="人文"/>
</bean>
1.4 使用SpringIoC解决项目中的耦合度问题
1.4.1 传统写法:Servlet对Service实现类存在依赖
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl1();
public void doGet(HttpServletRequest request,HttpServletResponse response){
userService.login();
}
}
1.4.2 解决方案
- Servlet
public class LoginServlet extends HttpServlet {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void doGet(HttpServletRequest request,HttpServletResponse response){
userService.login();
}
}
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService1" class="com.qfedu.service.impl.UserServiceImpl1"></bean>
<bean id="userService2" class="com.qfedu.service.impl.UserServiceImpl2"></bean>
<bean id="loginServlet" class="com.qfedu.servlets.LoginServlet">
<property name="userService" ref="userService2"/>
</bean>
</beans>
1.5 Bean的配置
bean标签,用来声明Spring容器对类的管理
- id/name属性 是当前bean的唯一标识
- class属性 用来指定被Spring容器管理的类路径
- scope属性
- lazy-init属性,设置Bean的初始化为懒初始化
- autowire属性,设置Bean的属性自动装配
1.5.1 Bean的生命周期
通过scope属性可以指定对象的生命周期
singleton 默认 ,设置当前bean为单例模式(饿汉)
- Spring容器启动创建对象(分配内存空间):创建对象—调用构造器—调用set方法—初始化方法
- 对象创建完成存放在Spring容器
- Spring容器关闭销毁对象
prototype 设置当前Bean为非单例模式
- Spring容器启动
不会
创建对象(加载配置文件)
- 调用getBean使用对象时创建对象:创建对象—调用构造器—调用set方法—初始化方法
- 对象创建完成可使用
- 对象使用完成之后被JVM垃圾回收
- scope配置
<bean id="type1" class="com.qfedu.entity.Type" scope="singleton">
<property name="typeId" value="10001"/>
<property name="typeName" value="人文"/>
</bean>
1.5.2 初始化和销毁方法
初始化方法:实例创建完成之后执行的方法
销毁方法:实例销毁时执行的方法
public class Type {
private int typeId;
private String typeName;
public void method1(){
System.out.println("-------init");
}
public void method2(){
System.out.println("-------destory");
}
}
<bean id="type1" class="com.qfedu.entity.Type" scope="singleton" lazy-init="true"
init-method="method1" destroy-method="method2">
<property name="typeId" value="10001"/>
<property name="typeName" value="人文"/>
</bean>
1.5.3 自动装配
Bean的属性(一般指的是对象属性)也可以通过自动装配来完成赋值,自动装配的两种方式:
- byType 根据当前对象属性的类型 从Spring容器中选择类型匹配的bean进行注入;如果没有找到对应类型的bean,则设置为null;如果找到多个类型匹配的Bean则抛出异常
- byName 根据当前对象属性的属性名 从Spring容器选择bean 进行注入;如果没有找到同名的bean则设置为null;如果根据属性名找到bean类型不匹配则抛出异常
<bean id="book" class="com.qfedu.entity.Book" autowire="byName"></bean>
1.6 Spring对象工厂的工作原理
Spring对象工厂原理:xml解析、反射
- Spring工作原理概念图
二、IoC注解配置
SpringIoC的使用,通过将我们创建的类声明给Spring对象工厂进行管理来实现对象创建和属性注入的;
Spring也提供了注解的配置形式,无需再xml文件中进行声明,直接在类中通过注解的形式进行声明即可。
2.1 配置声明使用注解
- 在spring配置文件applicationContext.xml添加context的命名空间
- 通过
context:annotation-config
标签声明使用注解 - 通过
context:component-scan
声明注解使用的范围
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.qfedu.entity"/>
</beans>
2.2 IoC常用注解
@Component /@Service/@Repository
- 类注解,声明类被Spring管理,相当于bean标签的作用
- value值相当于 bean标签的id属性,如果不设置value值,则默认id为 类名首字母小写
- @Service 用于声明Service; @Repository用于声明DAO ; @Component用于一般声明
@Autowired
-
属性注解/方法注解,用于声明当前属性为自动装配,默认根据byType类完成自动注入
-
@Autowired(required = false) 声明此自动装配非必须的,默认是必须的
-
当Spring容器由多个可以注入的Bean时,我们需要结合
@Qualifier
注解来指定注入的Bean@Autowired public void setType(@Qualifier("type1") Type type) { this.type = type; }
@Scope
- 类注解,用于声明当前类对象是否为单例模式,默认单例
- @Scope(“prototype”) 设置为非单例模式
@Lazy(false)
- 类注解,用于设置当前类的Bean是否为懒汉式(针对单例模式)、
- 默认值为true,@Lazy(false)设置为非懒汉式
@PostConstruct 和 @PreDestroy
- 方法注解,用于声明声明周期方法
- @PostConstruct 声明初始化方法
- @PreDestroy 声明销毁方法
@PostConstruct
public void method1(){
System.out.println("---init");
}
@PreDestroy
public void method2(){
System.out.println("----destory");
}