知乎大佬写的简单明了的ioc:
知乎大佬版ioc
IOC——控制反转(Inversion of Control)
对象的创建交给外部容器完成,这个就叫控制反转
控制反转的方法:DI(依赖注入)
控制反转的容器:ioc Container
这玩意就他喵是个——中介
没有中介的时候,我们写程序:
实体类—>class User{ }
Servlet–> class UserServlet{ Service service = new ServiceImpl(); }
3.Service–> class UserServiceImpl{ Repository repo = new RepositoryImpl(); }
- Repository–> class UserRepository{ …访问DB}
用户访问顺序:
Tomcat -> Servlet -> Service -> Repository
正转:
Servlet中需要
创建service对象调用service方法
service中需要
创建repo对象并调用方法访问数据库.
耦合度很高
使用IOC的依赖注入(DI)可以解决这个问题
1.环境搭建
IDEA
首先在IDEA中创建一个Maven工程
pom.xml
文件中添加配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.trygzb</groupId>
<artifactId>aispringioc</artifactId>
<version>1.0-SNAPSHOT</version>
<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.16.20</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>
Maven会自动下载spring需要的几个关键jar包
其中lombok工具可以使代码简化,整洁
创建实体类:
import lombok.Data;
@Data
public class Student {
private long id;
private String name;
private int age;
}
@Data会自动生成get,set方法
1.传统的开发方式,手动new Student()
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(22);
System.out.println(student);
}
}
运行结果
Student(id=1, name=张三, age=22)
2.通过 IoC 创建对象,在配置⽂件中添加需要管理的对象XML 格式的配置⽂件,⽂件名可以⾃定义
此处为:spring.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"
xmlns:context="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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<bean id="student" class="Student">
<property name="id" value="2"></property>
<property name="age" value="30"></property>
<property name="name" value="李四"></property>
</bean>
</beans>
通过id值获取类对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student sd = (Student) applicationContext.getBean("student");
System.out.println(sd);
运行结果:
Student(id=2, name=李四, age=30)
- 将对象作为属性值赋给学生对象
创建Adress类
import lombok.Data;
@Data
public class Address {
private Integer id;
private String address;
}
在Student类中添加
private Address address;
- 修改xml文件,使用
ref
将Adress赋给学生对象
<bean id="student" class="Student">
<property name="id" value="2"></property>
<property name="age" value="30"></property>
<property name="name" value="李四"></property>
<property name="address" ref="address"></property>
</bean>
<bean id="address" class="Address">
<property name="id" value="1"></property>
<property name="address" value="解放路"></property>
</bean>
运行结果:
Student
(id=2, name=李四, age=30, address=Address(id=1,address=解放路))
IoC底层原理
- 读取配置⽂件,解析 XML
- 通过反射机制实例化配置⽂件中所配置所有的 bean
通过运行实类获取bean
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("spring.xml");
Student student = (Student) applicationContext.getBean(Student.class);
System.out.println(student);
通过有参构造函数创建bean
- 在实体类Student中创建有参构造
- 配置文件
<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>
<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="Student">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
<property name="age" value="33"></property>
<property name="addresses">
<list>
<ref bean="address"></ref>
<ref bean="address2"></ref>
</list>
</property>
</bean>
<bean id="address" class="Address">
<property name="id" value="1"></property>
<property name="name" value="科技路"></property>
</bean>
<bean id="address2" class="Address">
<property name="id" value="2"></property>
<property name="name" value="⾼新区"></property>
</bean>
Scope的作用域
Spring 管理的 bean 是根据 scope 来⽣成的,表示 bean 的作⽤域,共4种,默认值是 singleton。
-
singleton:单例,表示通过 IoC 容器获取的 bean 是唯⼀的。Spring 在加载 spring.xml 时就会创建bean
-
prototype:原型,表示通过 IoC 容器获取的 bean 是不同的。当业务代码获取 IoC 容器中的 bean 时,Spring 才去调⽤⽆参构造创建对应的 bean
-
request:请求,表示在⼀次 HTTP 请求内有效。
-
session:回话,表示在⼀个⽤户会话内有效。
Spring 的继承
与 Java 的继承不同,Java 是类层⾯的继承,⼦类可以继承⽗类的内部结构信息;Spring 是对象层⾯的
继承,⼦对象可以继承⽗对象的属性值。
<bean id="student2" class="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="Address">
<property name="id" value="1"></property>
<property name="name" value="科技路"></property>
</bean> <bean id="address2" class="Address">
<property name="id" value="2"></property>
<property name="name" value="⾼新区"></property>
</bean>
<bean id="stu" class="Student" parent="student2">
<property name="name" value="李四"></property>
</bean>
⼦对象必须包含⽗对象的所有属性,同时可以在此基础上添加其他的属性
Spring 的依赖
与继承类似,依赖也是描述 bean 和 bean 之间的⼀种关系,配置依赖之后,被依赖的 bean ⼀定先创
建,再创建依赖的 bean,A 依赖于 B,先创建 B,再创建 A。
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:context="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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<bean id="student" class="Student" p:id="1" p:name="张三" p:age="22" p:address-ref="address">
</bean>
<bean id="address" class="Address" p:id="2" p:name="科技路">
</bean>
</beans>
Spring 的⼯⼚⽅法
- 静态实例方法
创建实例类
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
private Integer id;
private String name;
}
创建静态工厂类
public class StaticCarFactory {
private static Map<Integer,Car> carMap;
static {
carMap = new HashMap<Integer, Car>();
carMap.put(1, new Car(1,"宝马"));
carMap.put(2, new Car(2,"马自达"));
}
public static Car getCar(Integer id){
return carMap.get(id);
}
}
xml中配置静态工厂类
<bean id="car" class="StaticCarFactory" factory-method="getCar">
<constructor-arg value="2"></constructor-arg>
</bean>
测试类
public class Test1 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Car car = (Car) applicationContext.getBean("car");
System.out.println(car);
}
}
输出结果:
Car(id=2, name=马自达)
- 实例工厂方法
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 getCar(long id){
return carMap.get(id);
}
}
xml
<bean id="carFactory" class="com.southwind.factory.InstanceCarFactory"></bean>
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="1"></constructor-arg>
</bean>
自动装载
- byName:通过属性名⾃动装载
- byType:通过属性的数据类型⾃动装载
1.byName
<bean id="cars" class="Car">
<property name="id" value="1"></property>
<property name="name" value="宝⻢"></property>
</bean>
<bean id="person" class="Person" autowire="byName">
<property name="id" value="11"></property>
<property name="name" value="张三"></property>
</bean>
2.byType
<bean id="car" class="Car">
<property name="id" value="2"></property>
<property name="name" value="奔驰"></property>
</bean>
<bean id="person" class="Person" autowire="byType">
<property name="id" value="11"></property>
<property name="name" value="张三"></property>
</bean>
注:
byType 需要注意,如果同时存在两个及以上的符合条件的 bean 时,⾃动装载会抛出异常。