IOC -> XML
概念和作用
程序耦合:
在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。
解决耦合思路:反射 + 配置文件,减少 new
关键字的使用
工厂模式解耦:
实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用。这个读取配置文件,创建和获取三层对象的类就是工厂。
控制反转:
问题一:对象存哪 ?
由于我们是很多对象,肯定要找个集合来存,这时候有 Map
和 List
供选择。由于我们有查找需求,所以选择 Map
,把这个 Map
称为容器
问题二:什么是工厂 ?
工厂就是负责给我们从容器中获取指定对象的类
问题三:怎么获取对象 ?
主动方式:采用 new
的方式

被动方式:向工厂要,工厂为我们查找或者创建对象(这就是控制反转思想)

IOC 入门案例
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
创建接口及其配置类
public interface AccountService {
void saveAccount();
}
import com.service.AccountService;
public class AccountServiceImpl implements AccountService {
@Override
public void saveAccount() {
System.out.println("调用了 AccountServiceImpl 的 save 方法");
}
}
创建配置文件
<?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="accountService" class="com.service.impl.AccountServiceImpl"> </bean>
</beans>
主方法进行测试
import com.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationTest {
public static void main(String[] args) {
// 使用 ApplicationContext
ApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
AccountService accountService = application.getBean("accountService", AccountService.class);
accountService.saveAccount();
//使用 BeanFactory
Resource resoure = new ClassPathResource("application.xml");
BeanFactory factory = new XmlBeanFactory(resoure);
AccountService as = (AccountService) factory.getBean("accountService");
as.saveAccount();
}
}
执行结果

了解常用类
ApplicationCOntext
的三个常用类
ClassPathXmlApplicationContext
:它可以加载类路径下的配置文件,要求配置文件必须在类路径下
FileSystemXmlApplicationContext
:它可以加载磁盘任意路径下的配置文件(必须要有访问权限)
AnnotationConfigApplicationContext
:基于注解使用的,它不需要配置文件,采用配置类和各种注解来配置
核心容器的两个接口
ApplicationContext
:单例适用,它在构建核心容器时,创建对象采取的策略是采用立即加载,也就是说,只要已读取完配置文件马上就创建配置文件中配置的对象
BeanFactory
:多例适用,它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式,也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象
IOC 中的 Bean 标签
bean
标签的常用属性
scope
属性详解
证明scope
(使用上面定义的 accountService
):
<!--测试单例多例-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl" scope="`singleton`"></bean>
//测试 scope:singleton
AccountService accountService1 = application.getBean("accountService", AccountService.class);
AccountService accountService2 = application.getBean("accountService", AccountService.class);
System.out.println(accountService1 == accountService2);*///true
//测试 scope : prototype
AccountService accountService3 = application.getBean("accountService", AccountService.class);
AccountService accountService4 = application.getBean("accountService", AccountService.class);
System.out.println(accountService3 == accountService4);//false
实例化bean
的方式
使用默认无参构造函数:在 spring
的配置文件中使用 bean
标签,配以 id
和 class
属性之后,且没有其他属性和标签时采用的是默认构造函数创建 bean
对象,此时如果类中没有默认构造函数,则对象无法创建
<bean id="accountService" class="com.service.impl.AccountServiceImpl" scope="singleton"></bean>
使用普通工厂中的方法创建对象:使用某个类中的方法创建对象,并存入 spring
容器中
<!-- factory-bean属性:用于指定实例工厂bean的id -->
<!-- factory-method属性:用于指定实例工厂中创建对象的方法 -->
<!--创建工厂 Bean-->
<bean id="instanceFactory" class="com.factory.InstanceFactory"></bean>
<!--使用工厂中的普通方法创建对象-->
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
// java 工厂
public class InstanceFactory {
private AccountService accountService = new AccountServiceImpl();
public AccountService getAccountService(){
return accountService;
}
}
使用工厂中的静态方法创建对象: 使某个类中的静态方法创建对象,并存入spring容器中
<!-- id属性:指定bean的id,用于从容器中获取 -->
<!-- class属性:指定静态工厂的全限定类名 -->
<!-- factory-method属性:指定生产对象的静态方法 -->
<!--使用静态方法创建对象-->
<bean id="accountService" class="com.factory.StaticFactory" factory-method="getAccountService"></bean>
// java 工厂
public class StaticFactory {
private static AccountService accountService = new AccountServiceImpl();
public static AccountService getAccountService(){
return accountService;
}
}
Spring 依赖注入
构造函数注入:
测试下列情况所使用的 Person
类
import java.util.Date;
public class Person {
private String name;
private int age;
private Date date;
// 下列情况演示中使用的构造方法
public Person(String name,int age,Date date){
this.name = name;
this.age = age;
this.date = date;
}
}
情况一:index + value / index + ref
<bean id="date" class="java.util.Date"></bean>
<bean id="p" class="com.domain.Person">
<constructor-arg index="0" value="张三"></constructor-arg>
<constructor-arg index="1" value="15"></constructor-arg>
<constructor-arg index="2" ref="date"></constructor-arg>
</bean>
情况二:type + value / type + ref
<bean id="date" class="java.util.Date"></bean>
<bean id="p1" class="com.domain.Person">
<constructor-arg type="java.lang.String" value="张三"></constructor-arg>
<constructor-arg type="int" value="15"></constructor-arg>
<constructor-arg type="java.util.Date" ref="date"></constructor-arg>
</bean>
情况三:name + value / name + ref
<bean id="date" class="java.util.Date"></bean>
<bean id="p2" class="com.domain.Person">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="15"></constructor-arg>
<constructor-arg name="date" ref="date"></constructor-arg>
</bean>
测试验证
// 测试的代码
ApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
Person p = application.getBean("p", Person.class);
Person p1 = application.getBean("p1", Person.class);
Person p2 = application.getBean("p2", Person.class);
System.out.println(p);
System.out.println(p1);
System.out.println(p2);

Set 方法注入
说明:使用的是上面的 Person
类,但是需要添加 Getter / Setter
方法,同时跟上面的验证使用的是同样的方法。
<bean id="p3" class="com.domain.Person">
<property name="name" value="张三"></property>
<property name="age" value="15"></property>
<property name="date" ref="date"></property>
</bean>
复杂类型的注入
给数组类型注入
测试下列情况所使用的的 School
类
import java.util.Arrays;
public class School {
private String[] schoolNames = new String[3];
public School() {
}
public School(String[] schoolNames) {
this.schoolNames = schoolNames;
}
public String[] getSchoolNames() {
return schoolNames;
}
public void setSchoolNames(String[] schoolNames) {
this.schoolNames = schoolNames;
}
toString(); // 自行补充
}
情况一 :使用构造方法
<bean id="s2" class="com.domain.School">
<constructor-arg name="schoolNames">
<array>
<value>重庆大学</value>
<value>重庆文理学院</value>
<value>重庆师范大学</value>
</array>
</constructor-arg>
</bean>
情况二:使用 set
方法
<bean id="s1" class="com.domain.School">
<property name="schoolNames">
<array>
<value>重庆大学</value>
<value>重庆师范大学</value>
<value>重庆文理学院</value>
</array>
</property>
</bean>
给 List
类型进行注入
测试下列情况所使用的的 Dates
类
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Dates {
private List<Date> dates = new ArrayList<>();
public Dates() {
}
public Dates(List<Date> dates) {
this.dates = dates;
}
public List<Date> getDates() {
return dates;
}
public void setDates(List<Date> dates) {
this.dates = dates;
}
toString(); // 自行补充
}
情况一 :使用构造方法
<bean id="dates1" class="com.domain.Dates">
<constructor-arg name="dates">
<list>
<ref bean="date"></ref>
<ref bean="date"></ref>
<ref bean="date"></ref>
</list>
</constructor-arg>
</bean>
情况二:使用 set
方法
<bean id="dates2" class="com.domain.Dates">
<property name="dates">
<list>
<ref bean="date"></ref>
<ref bean="date"></ref>
</list>
</property>
</bean>
给 Set
类型进行注入
测试下列情况所使用的的 Maps
类
import java.util.*;
public class Dates {
private Set<Date> dates = new HashSet<>();
public Dates() {
}
public Dates(Set<Date> dates) {
this.dates = dates;
}
public Set<Date> getDates() {
return dates;
}
public void setDates(Set<Date> dates) {
this.dates = dates;
}
toString(); // 自行添加
}
情况一 :使用构造方法
<bean id="set2" class="com.domain.Dates">
<constructor-arg name="dates">
<set>
<ref bean="date"></ref>
<ref bean="date"></ref>
<ref bean="date"></ref>
</set>
</constructor-arg>
</bean>
情况二:使用 set
方法
<bean id="set1" class="com.domain.Dates">
<property name="dates">
<set>
<ref bean="date"></ref>
<ref bean="date"></ref>
<ref bean="date"></ref>
</set>
</property>
</bean>
给 Map
类型进行注入
测试下列情况所使用的的 Maps
类
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class Maps {
private Map<String, Date> map = new HashMap<>();
public Maps() {
}
public Maps(Map<String, Date> map) {
this.map = map;
}
public Map<String, Date> getMap() {
return map;
}
public void setMap(Map<String, Date> map) {
this.map = map;
}
toString(); // 自行添加
}
情况一 :使用构造方法
<bean id="m1" class="com.domain.Maps">
<constructor-arg name="map">
<map>
<entry key="1" value-ref="date"></entry>
<entry key="2">
<ref bean="date"></ref>
</entry>
</map>
</constructor-arg>
</bean>
情况二:使用 set
方法
<bean id="m2" class="com.domain.Maps">
<property name="map">
<map>
<entry key="1" value-ref="date"></entry>
<entry key="2">
<ref bean="date"></ref>
</entry>
</map>
</property>
</bean>
autowire
属性详解
证明 autowire
属性所使用的类
public class Man {
private Person person;
public Man() {
}
public Man(Person person) {
this.person = person;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
toString(); // 自行添加
}
import java.util.Date;
public class Person {
private String name;
private int age;
private Date date;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name,int age,Date date){
this.name = name;
this.age = age;
this.date = date;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
toString(); // 自行添加
}
测试代码:
ApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
//测试 autowire
Person person = application.getBean("person",Person.class);
Man man = application.getBean("man",Man.class);
System.out.println(person);
System.out.println(man);
证明 byName
属性
<bean id="date" class="java.util.Date"></bean>
<bean id="person" class="com.domain.Person">
<property name="name" value="LEE"/>
<property name="age" value="20"/>
<property name="date" ref="date"/>
</bean>
<bean id="man" class="com.domain.Man" autowire="byName"></bean>

证明 byType
属性
情况一 :IOC
容器中只有一个该类型的 bean
<bean id="date" class="java.util.Date"></bean>
<bean id="person" class="com.domain.Person">
<property name="name" value="LEE"/>
<property name="age" value="20"/>
<property name="date" ref="date"/>
</bean>
<bean id="man" class="com.domain.Man" autowire="byType"></bean>

情况二:IOC
容器中有多个该类型的 bean
<bean id="date" class="java.util.Date"></bean>
<bean id="p3" class="com.domain.Person">
<property name="name" value="张三"></property>
<property name="age" value="15"></property>
<property name="date" ref="date"></property>
</bean>
<bean id="person" class="com.domain.Person">
<property name="name" value="LEE"/>
<property name="age" value="20"/>
<property name="date" ref="date"/>
</bean>
<bean id="man" class="com.domain.Man" autowire="byType"></bean>

测试 constructor
情况一:有相对应的构造器
<bean id="date" class="java.util.Date"></bean>
<bean id="person" class="com.domain.Person">
<property name="name" value="LEE"/>
<property name="age" value="20"/>
<property name="date" ref="date"/>
</bean>
<bean id="man" class="com.domain.Man" autowire="constructor"></bean>

情况二:没有相对应的构造器(还是使用情况一的配置,只是修改 Man
类)
public class Man {
private Person person;
public Man() {
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
toString(); // 自行添加
}