Spring IOC(控制反转)是Spring框架的核心特性,彻底改变了Java对象管理的方式。传统开发中对象之间的引用需要通过new关键字手动创建,而Spring IOC将对象的创建和依赖管理交给容器统一处理,实现了控制权的反转

Spring

Spring IOC的实现用到了设计模式:简单工厂,他也是从简单工厂进化而来的,下面我们看看Spring的IOC是如何进化来的。

image

一、简单工厂模式

1.1 接口Fruit

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.study.service;

/**
* 简单工厂模式
* 抽象接口
*
* @author Howe Hsiang
*/
public interface Fruit {
void eat();
}


1.2 实现类Apple和Orange

Apple实现类:

1
import com.study.service.Fruit;
1
2
3
/**
* 简单工厂模式
* 实现类Apple
  • 1
    * @author Howe Hsiang
    */
    1
    public class Apple implements Fruit {
1
2
3
@Override
public void eat() {
System.out.println("吃苹果");
}

`Orange实现类:```java

1
package com.study.service.Impl;
1
2
/**
* 实现类Orange
  • */
    1
    public class Orange implements Fruit {
1
System.out.println("吃橘子");
}

`#### 1.3 工厂类SimpleFactory```java

1
package com.study.controller;
1
2
import com.study.service.Impl.Apple;
import com.study.service.Impl.Orange;
1
2
/**
* 工厂类

*/

1
public class SimpleFactory {
1
public static Fruit getInstance(String className){
1
2
3
Fruit f = null;
if(className.equals("apple")){
f = new Apple();
    }
1
2
if(className.endsWith("orange")){
f = new Orange();
    }
1
return f;
}

}

`#### 1.4 测试类SimpleFactoryTest```java

1
import org.junit.Test;
1
2
/**
* 测试简单工厂模式
  • */
    1
    public class SimpleFactoryTest extends BaseTest {
1
2
@Test
public void getInstance() {
1
2
3
//苹果
Fruit apple = SimpleFactory.getInstance("apple");
apple.eat();
1
2
3
//橘子
Fruit orange = SimpleFactory.getInstance("orange");
orange.eat();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


### 二、反射+简单工厂模式

如果增加了水果,比如香蕉,那么在工厂类里面也要进行相关的修改了,这样不合理,而java的反射机制可以解决这个问题.

#### 2.1 反射工厂类ReflexFactory


/**
* 反射+简单工厂模式
* 反射工厂类
*/

public class ReflexFactory {


try {
f = (Fruit) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}

}


`#### 2.2 测试类ReflexFactoryTest```java
/**
* 测试反射+简单工厂模式
*
*/
public class ReflexFactoryTest extends BaseTest {

@Test

//苹果
Fruit apple = ReflexFactory.getInstance("com.study.service.Impl.Apple");

//橘子
Fruit orange = ReflexFactory.getInstance("com.study.service.Impl.Orange");
}


三、反射+简单工厂模式+xml配置文件

3.1 实例配置类PropertiesOperate

1
2
3
4
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;
1
2
3
/**
* 反射+简单工厂模式+xml配置文件
* 实例配置类PropertiesOperate
  • */
1
public class PropertiesOperate {
1
private Properties pro = null;
1
String url = this.getClass().getResource("/").getPath();
1
private File file = new File(url+"fruit.properties");
1
2
3
4
5
public PropertiesOperate(){
this.pro = new Properties();
if(file.exists()){
try {
pro.loadFromXML(new FileInputStream(file));
        }
1
2
}else{
this.save();
    }
1
2
3
4
5
private void save(){
this.pro.setProperty("apple","com.study.service.Impl.Apple");
this.pro.setProperty("orange", "com.study.service.Impl.Orange");
try {
this.pro.storeToXML(new FileOutputStream(this.file),"Fruit");
    }
1
2
public Properties getProperties(){
return this.pro;
}

}

`#### 3.2 测试类PropertiesOperateTest```java

1
2
/**
* 测试反射+简单工厂模式+xml配置文件
  • */
    1
    public class PropertiesOperateTest extends BaseTest {
1
2
@Test
public void getProperties(){
1
Properties pro=new PropertiesOperate().getProperties();
1
2
//苹果
Fruit apple = ReflexFactory.getInstance(pro.getProperty("apple"));
1
2
//橘子
Fruit orange = ReflexFactory.getInstance(pro.getProperty("orange"));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149


### 四、终极版本Spring IOC

以后如果要增加新的水果类,都要在这个配置文件里面登记。这时我们可以说配置文件可以控制程序的执行,现在看起来有点像spring的ioc了。下面我们来看看Spring IOC是如何实现的。

#### 4.1 实体类Person和Grade

实体类Person:


package com.study.entity;

/**
* 人类
*/
public class Person {

private String name;

private int age;

private Grade grade;

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;
}

public Grade getGrade() {
return grade;
}

public void setGrade(Grade grade) {
this.grade = grade;
}


`实体类Grade:```java
/**
* 科目
*/
public class Grade {

private int math;

private int english;

public int getMath() {
return math;
}

public void setMath(int math) {
this.math = math;
}

public int getEnglish() {
return english;
}

public void setEnglish(int english) {
this.english = english;
}


`#### 4.2 配置文件Bean.xml```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-->

<!--第一个Bean,是一个Person类,id名字随便取,还要写上类的全名-->
<bean id="Person" class="com.study.entity.Person">
<!--下面开始把这个类里面的所有属性列出来,并赋值,至于你说难道一定要赋值吗?我想可以,我刚学,不知道-->
<property name="name">
<!--这里的名字是通过程序里面的set来赋值的,不信你去掉程序里面相关的set,就出错了-->
<value>Howe Hsiang</value>
</property>

<property name="age">
<value>23</value>

<!--这里有点特别,这个grade变量是一个对象,和一般的变量要区别对待-->
<property name="grade">
<!--这里指向了本配置文件里面一个名字叫Grade(即id=Grade)的bean-->
<ref bean = "Grade"/>
</bean>

<!--同上-->
<bean id="Grade" class="com.study.entity.Grade">
<property name="math">
<value>99</value>

<property name="english" >
<value>59</value>

</beans>

`#### 4.3 测试类SpringIocTest```java
import com.study.controller.BaseTest;
import com.study.entity.Grade;
import com.study.entity.Person;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;


/**
* 测试类
*/
public class SpringIocTest extends BaseTest {

@Test
public void getSpringIocInfo() {

//把input扔到工厂里面去,这个工厂就能为你提供实例了(装载配置文件)
BeanFactory factory = new ClassPathXmlApplicationContext("Bean.xml");

//你要一个叫Person的东西,那好,工厂就去找“Person"给你
Person person =(Person) factory.getBean("Person");
Grade grade=(Grade)factory.getBean("Grade");

//person可以调用里面相关的方法,就相当于new了一个Person一样
System.out.println(
"姓名:"+person.getName()+ "; " +
"年龄:"+person.getAge() + "; " +
"数学成绩:"+grade.getMath()+ "; " +
"英语成绩:"+grade.getEnglish());
}

}

五、其他

1、关于Spring读取配置文件的方法

applicationcontext—

FileSystemXmlApplicationContext—这个方法是从文件绝对路径加载配置文

1
ClassPathXmlApplicationContext---这个方法是从classpath下加载配置文件(适合于相对路径方式加载)

XmlWebApplicationContext—-专为web工程定制的方法,推荐Web项目中使用。

beanfactory—

1
ClassPathResource --- 从系统的类路径中加载 

FileSystemResource — 从文件系统加载,比如说自己指定配置文件的全路径

InputStreamResource — 从输入流中加载

ServletContextResource — 从Servlet 上下文环境中加载

UrlResource — 从指定的Url加载


2、BeanFactory和ApplicationContext的区别

ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。
ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:

• MessageSource, 提供国际化的消息访问

• 资源访问,如URL和文件

• 事件传播

• 载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如应用的web层

最主要的就是BeanFactory延迟加载,当使用到getBean的时候才会抛异常,而ApplicationContext在刚开始启动加载的时候就会抛出异常,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。

1
*注:* [SpringIOC详解](https://github.com/Hosiang1026/springioc)

本文标题: Spring框架核心IOC开发

发布时间: 2019年03月25日 00:00

最后更新: 2025年12月30日 08:54

原始链接: https://haoxiang.eu.org/92e11628/

版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!

× 喜欢就赞赏一下呗!
打赏二维码