IOC :Ioc—Inversion of Control,控制反转,Ioc不是某种技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
传统Java SE程序设计: 直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;在Ioc中, 容器控制对象的活动,主要是外部资源获取。在传统应用程序中,是由我们自己在对象中主动控制去直接获取依赖对象,也就是正向控制,即"正转";而所谓反转则是由容器来帮忙创建及注入依赖对象。
DI: Dependency Injection,"依赖注入":组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
* 在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和时机自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后将对象存储在容器里,当A对象需要使用B对象时,Spring就从存放对象的容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题,A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
* 控制反转Ioc是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 Ioc容器,也就是去了之前的依赖关系,上下游都依赖Ioc容器了,通过Ioc容器来建立它们之间的关系。
现在来手动模拟一下Spring IOC:
1.pom文件
<?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>ioc-demo</groupId>
<artifactId>ioc-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
</project>
2.实体类 Stuff
public class Stuff {
public static String getName() {
return name;
}
public static void setName(String name) {
Stuff.name = name;
}
public static String getGender() {
return gender;
}
public static void setGender(String gender) {
Stuff.gender = gender;
}
public static Integer getAge() {
return age;
}
public static void setAge(Integer age) {
Stuff.age = age;
}
public static String getBranch() {
return branch;
}
public static void setBranch(String branch) {
Stuff.branch = branch;
}
public void introduce() {
System.out.println("Hello! my name is " + name + " " + gender + " i'm " + age + " years old I work in the " + branch + " department");
}
private static String name;
private static String gender;
private static Integer age;
private static String branch;
}
3.Bean 的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="user1" class="bean.Stuff">
<property name="name" value="Jack"></property>
<property name="gender" value="male"></property>
<property name="age" value="22"></property>
<property name="branch" value="financial"></property>
</bean>
<bean id="user2" class="bean.Stuff">
<property name="name" value="Cali"></property>
<property name="gender" value="female"></property>
<property name="age" value="25"></property>
<property name="branch" value="development"></property>
</bean>
</beans>
4.配置bean的配置中心 ClassPathXmlApplicationContext
public class ClassPathXmlApplicationContext {
private String xmlPath;
public ClassPathXmlApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
}
/**
* 解析xml文件
*
* @param beanName
*/
public Object getBean(String beanName) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
//1、读取xml配置文件
SAXReader saxReader = new SAXReader();
Document read = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(xmlPath));
Element rootElement = read.getRootElement();
//System.out.println("根节点的名称: " + rootElement.getName());
List<Element> elements = rootElement.elements();
Object obj = null;
for (Element sonEle : elements) {
//2、获取到每个bean配置,获得class地址
String sonBeanId = sonEle.attributeValue("id");
if (!beanName.equals(sonBeanId)) {
continue;
}
String beanClassPath = sonEle.attributeValue("class");
//3、拿到class地址,进行反射技术实例化对象,使用反射api为私有属性赋值
Class<?> forName = Class.forName(beanClassPath);
obj = forName.newInstance();
List<Element> sonSoneleme = sonEle.elements();
for (Element element : sonSoneleme) {
String name = element.attributeValue("name");
String value = element.attributeValue("value");
Field declaredField = forName.getDeclaredField(name);
declaredField.setAccessible(true);
if (name.equals("age")) {
declaredField.set(obj, Integer.parseInt(element.attributeValue("value")));
} else {
declaredField.set(obj, value);
}
}
}
return obj;
}
}
5.主类
public class CoreService {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, DocumentException {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("person.xml");
Stuff user = (Stuff) classPathXmlApplicationContext.getBean("user1");
System.out.println("user >>> ");
user.introduce();
}
}
代码如上 现在执行一下 >>>>>
1. 可以看到 在获取bean的时候,首先通过saxReader document对象,并根据Element rootElement = read.getRootElement(); 获取到了根节点 进而通过根节点 rootElement.elements() 获取到了根节点中包含所有的元素
2.遍历所有Element 根据传入的 BeanId 判定需要获取的是哪个bean
if (!beanName.equals(sonBeanId)) { continue; }
3.利用反射实例化对象
Class<?> forName = Class.forName(beanClassPath); obj = forName.newInstance();
4.为对象的各个属性注入值 并返回这个对象
String name = element.attributeValue("name"); String value = element.attributeValue("value"); Field declaredField = forName.getDeclaredField(name); declaredField.setAccessible(true); if (name.equals("age")) { declaredField.set(obj, Integer.parseInt(element.attributeValue("value"))); } else { declaredField.set(obj, value); }
5.运行结果