Spring IoC所解决的问题
Spring IoC(Inversion of Control),即控制反转,也叫依赖注入DI(Dependency Injection)是将程序的控制权交给了Spring容器,从而达到控制的反转。
- IoC降低了程序之间的耦合度。在不使用Spring框架的前提下,我们必须以创建对象的方式对两个类进行强耦合,这样,会导致我们程序的健壮性太低。如果我们程序所依赖的类出现问题,那么程序就有可能无法进行编译。而把对象创建的权利交给Spring,降低了程序之间的耦合度。
- 程序员不需要考虑对象的创建管理,而更加专注于业务逻辑。
实现步骤
Spring提供了两种IoC容器:ApplicationContext和BeanFactory。这篇博客简单的写一个简单的Bean工厂。步骤如下:
- 读取xml文件,解析节点,得到类名和属性名
- 利用反射和类加载创建该类的实例并设置其属性值
- 创建set方法利用set方法进行注入
程序代码
由于我们需要对xml文件进行解析,所以这里要引入Dom4j.jar。
- 最重要的一点,编写自定义的配置文件。这里仿照Spring的配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="studentDao" class="com.spring.dao.impl.StudentDao">
<property name="str" value="我是学生"></property>
</bean>
<bean id="teacherDao" class="com.spring.dao.impl.TeacherDao">
<property name="str" value="我是老师"></property>
</bean>
</beans>
- 实现IoC的核心代码。
package com.spring.core;
import java.io.File;
import java.lang.reflect.Field;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class BeanFactory {
private Document document;
String contextConfigLocation = "src/spring.xml";
public BeanFactory() {
File file = new File(contextConfigLocation);
SAXReader reader = new SAXReader();
try {
document = reader.read(file);
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Object getBean(String beanName) {
Element root = document.getRootElement();
List<Element> elements = root.elements();
String beanLocation = null;
String beanPropertyName = null;
String beanPropertyVal = null;
for(Element e : elements) {
if(e.attributeValue("id").equals(beanName)) {
beanLocation = e.attributeValue("class");
List<Element> propertyElements = e.elements();
for(Element pE : propertyElements) {
beanPropertyName = pE.attributeValue("name");
beanPropertyVal = pE.attributeValue("value");
}
}
}
try {
Class<?> clazz = Class.forName(beanLocation);
Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField(beanPropertyName);
field.setAccessible(true);
field.set(obj, beanPropertyVal);
return obj;
} catch (ClassNotFoundException e1) {
System.out.println(beanLocation + "类未找到");
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
return null;
}
}
- DAO层实现
//IuserDao.java
package com.spring.dao;
public interface IUserDao {
public void print();
}
//StudentDao.java
package com.spring.dao.impl;
import com.spring.dao.IUserDao;
public class StudentDao implements IUserDao{
String str;
@Override
public void print() {
System.out.println(str);
}
}
//TeacherDao.java
package com.spring.dao.impl;
import com.spring.dao.IUserDao;
public class TeacherDao implements IUserDao{
String str;
@Override
public void print() {
System.out.println(str);
}
}
- Service层实现
package com.spring.service;
import com.spring.dao.IUserDao;
public class UserService {
private IUserDao userDao;
//我们要使用set方法手动注入
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
public void print() {
System.out.println("我是service层方法");
userDao.print();
}
}
- Controller层实现。
package com.spring.controller;
import com.spring.core.BeanFactory;
import com.spring.dao.impl.TeacherDao;
import com.spring.service.UserService;
public class TestController {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory();
UserService userService = new UserService();
//这里是我们程序运行时需要更改的地方
userService.setUserDao((IUserDao)beanFactory.getBean("teacherDao"));
userService.print();
}
}
程序测试
我们只需改变其所注入的Bean的名称。