Spring IoC概述
-
Spring框架两大核心机制(IoC和AOP)
- IoC(控制反转)/ID(依赖注入)
- AOP(面向切面编程)
-
Spring是一个企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层,开发者可以自主选择组件。
- MVC: Struts、Spring MVC
- OBMapping: Hibernate、MyBatis、Spring Data
-
Spring体系结构
-
什么是控制反转
- 在传统的程序开发中,需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动new出来的
- 但在Spring框架中创建对象的工作不再由调用者来完成,而是交给IoC容器来创建,再推送给调用者,整个流程完成反转,所以是控制反转。
-
如何使用IoC
- 创建Maven工程,pom.xml添加依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.11.RELEASE</version> </dependency> <!--简化实体类的开发--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> <scope>provided</scope> </dependency> </dependencies>
- 创建实体类Student
package com.southwind.entity; import lombok.Data; @Data public class Student { private long id; private String name; private int age; }
- 传统的开发方式,手动new Student
Student student = new Student(); student.setId(1L); student.setName("张三"); student.setAge(22); System.out.println(student);
- 通过IoC创建对象,在配置文件中添加需要管理的对象,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-3.0.xsd"> <bean id="student" class="com.southwind.entity.Student"> <property name="id" value="1"></property> <property name="name" value="张三"></property> <property name="age" value="22"></property> </bean> </beans>
- 从IoC中获取对象,通过id获取
//加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); Student student = (Student) applicationContext.getBean("student"); System.out.println(student);
配置文件
-
通过配置
bean
标签来完成对象的管理id
:对象名class
:对象的模板类(所有交给IoC容器来管理的类必须有无参构造函数,因为Spring底层是通过反射机制来创建对象,调用的是无参构造)
-
对象的成员变量通过
property
标签完成赋值name
:成员变量名value
:成员变量值(基本数据类型,String可以直接赋值,如果是引用类型,不能通过value赋值)ref
:将IoC中的另一个bean赋值给当前的成员变量(DI)
<bean id="student" class="com.southwind.entity.Student"> <property name="id" value="1"></property> <property name="name" value="张三"></property> <property name="age" value="22"></property> <property name="address" ref="address"></property> </bean> <bean id="address" class="com.southwind.entity.Address"> <property name="id" value="1"></property> <property name="name" value="科技路"></property> </bean>
IoC底层原理
- 读取配置文件,解析XML
- 通过反射机制实例化配置文件中所配置的所有bean
通过运行时类获取bean
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student student = (Student) applicationContext.getBean(Student.class);
System.out.println(student);
这种方式存在一个问题,配置文件中的一个数据类型的对象只能有一个实例,否则会抛出异常,因为没有唯一的bean。
通过有参构造创建bean
- 在实体类中创建对应的有参构造函数
- 配置文件
<bean id="student3" class="com.southwind.entity.Student">
<constructor-arg name="id" value="3"></constructor-arg>
<constructor-arg name="name" value="小明"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="address" ref="address"></constructor-arg>
</bean>
(通过name)或(通过下标)
<bean id="student3" class="com.southwind.entity.Student">
<constructor-arg index="0" value="3"></constructor-arg>
<constructor-arg index="2" value="18"></constructor-arg>
<constructor-arg index="1" value="小明"></constructor-arg>
<constructor-arg index="3" ref="address"></constructor-arg>
</bean>
给bean注入集合
<bean id="student" class="com.southwind.entity.Student">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="22"></property>
<property name="addresses">
<list>
<ref bean="address"></ref>
<ref bean="address2"></ref>
</list>
</property>
</bean>
<bean id="address" class="com.southwind.entity.Address">
<property name="id" value="1"></property>
<property name="name" value="科技路"></property>
</bean>
<bean id="address2" class="com.southwind.entity.Address">
<property name="id" value="2"></property>
<property name="name" value="高新区"></property>
</bean>
spoce 作用域
- Spring管理的bean是根据scope来生成的,表示bean的作用域,共4种,默认是singletion
- singleton:单例,表示通过IoC容器获取的bean是唯一的
- prototype:原型,表示通过IoC容器获取的bean是不同的
- request:请求,表示在一次HTTP请求内有效
- session:回话,表示在一个用户会话内有效
- request和session只适用于Web项目,大多数情况下,使用单例和原型较多
- prototype模式党业务代码获取IoC容器中的bean时,Spring才会去调用无参构造创建对应的bean
- singleton模式无论业务代码是否获取IoC容器中的bean,Spring在加载spring.xml时就会创建bean
Spring的继承
- 与java的继承不同,java是类层面的继承,子类可以继承父类的内部结构信息;Spring是对象层面的继承,子对象可以继承父对象的属性值
<bean id="student2" class="com.southwind.entity.Student">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="22"></property>
<property name="addresses">
<list>
<ref bean="address"></ref>
<ref bean="address2"></ref>
</list>
</property>
</bean>
<bean id="stu" class="com.southwind.entity.Student" parent="student2">
<property name="name" value="李四"></property>
</bean>
<bean id="address" class="com.southwind.entity.Address">
<property name="id" value="1"></property>
<property name="name" value="科技路"></property>
</bean>
<bean id="address2" class="com.southwind.entity.Address">
<property name="id" value="2"></property>
<property name="name" value="高新区"></property>
</bean>
- Spring的继承关注点在于具体的对象,而不在于类,即不同的两个类的实例化对象可以完全继承,前提是子对象必须包含父对象的所有属性,同时可以在此基础上添加其他属性。
Spring的依赖
- 与继承相似,依赖也是描述bean和bean之间的一种关系,配置依赖之后,被依赖的bean一定先创建,再创建依赖的bean,例如A依赖于B,先创建B,再创建A
<?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-3.0.xsd">
<bean id="user" class="com.southwind.entity.User" depends-on="student"></bean>
<bean id="student" class="com.southwind.entity.Student"></bean>
</beans>
Spring的p命名空间
- p命名空间是对IoC/DI的简化操作,使用p命名空间可以更加方便的完成bean的配置以及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"
xmlns:contest="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<bean id="student" class="com.southwind.entity.Student" p:id="1" p:name="张三" p:age="22" p:address-ref="address"></bean>
<bean id="address" class="com.southwind.entity.Address" p:id="2" p:name="科技路"></bean>
</beans>
Spring的工厂方法
-
IoC通过工厂模式创建bean的方式有两种
- 静态工厂方法
package com.southwind.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class Car { private long id; private String name; }
package com.southwind.factory; import com.southwind.entity.Car; import java.util.HashMap; import java.util.Map; public class StaticCarFactory { private static Map<Long, Car> carMap; static{ carMap = new HashMap<Long, Car>(); carMap.put(1L,new Car(1L,"宝马")); carMap.put(2L,new Car(2L,"奔驰")); } public static Car getCar(long id){ return carMap.get(id); } }
<!-- 配置静态工厂创建Car --> <bean id="car" class="com.southwind.factory.StaticCarFactory" factory-method="getCar"> <constructor-arg value="2"></constructor-arg> </bean>
- 实例工厂方法
package com.southwind.factory; import com.southwind.entity.Car; import java.util.HashMap; import java.util.Map; public class InstanceCarFactory { private Map<Long, Car> carMap; public InstanceCarFactory(){ carMap = new HashMap<Long, Car>(); carMap.put(1L,new Car(1L,"宝马")); carMap.put(2L,new Car(2L,"奔驰")); } public Car gerCar(long id) { return carMap.get(id); } }
<!-- 配置实例工厂 bean --> <bean id="carFactory" class="com.southwind.factory.InstanceCarFactory"></bean> <!-- 配置实例工厂 创建car --> <bean id="car2" factory-bean="carFactory" factory-method="gerCar"> <constructor-arg value="1"></constructor-arg> </bean>
IoC自动装载(Autowire)
-
IoC负责创建对象,DI负责完成对象的依赖注入,通过配置property标签的ref属性来完成,同时Spring提供了另外一种更加简便的依赖注入方式:自动装载,不需要手动配置property,IoC容器会自动选择bean完成注入
-
自动装载有两种方式:
- byName:通过属性名自动装载
<bean id="car" class="com.southwind.entity.Car"> <property name="id" value="1"></property> <property name="name" value="宝马"></property> </bean> <bean id="person" class="com.southwind.entity.Person" autowire="byName"> <property name="id" value="1"></property> <property name="name" value="张三"></property> </bean>
- byType:通过属性的数据类型自动装载
使用时需要注意,如果同时存在两个及以上的符合条件的bean时,自动装载会抛出异常
<bean id="car1" class="com.southwind.entity.Car"> <property name="id" value="1"></property> <property name="name" value="宝马"></property> </bean> <bean id="person" class="com.southwind.entity.Person" autowire="byType"> <property name="id" value="1"></property> <property name="name" value="张三"></property> </bean>