【Java】手写Spring-IoC

Spring IoC所解决的问题

Spring IoC(Inversion of Control),即控制反转,也叫依赖注入DI(Dependency Injection)是将程序的控制权交给了Spring容器,从而达到控制的反转。

  • IoC降低了程序之间的耦合度。在不使用Spring框架的前提下,我们必须以创建对象的方式对两个类进行强耦合,这样,会导致我们程序的健壮性太低。如果我们程序所依赖的类出现问题,那么程序就有可能无法进行编译。而把对象创建的权利交给Spring,降低了程序之间的耦合度。
  • 程序员不需要考虑对象的创建管理,而更加专注于业务逻辑。
实现步骤

Spring提供了两种IoC容器:ApplicationContext和BeanFactory。这篇博客简单的写一个简单的Bean工厂。步骤如下:

  1. 读取xml文件,解析节点,得到类名和属性名
  2. 利用反射和类加载创建该类的实例并设置其属性值
  3. 创建set方法利用set方法进行注入
程序代码

由于我们需要对xml文件进行解析,所以这里要引入Dom4j.jar。

  1. 最重要的一点,编写自定义的配置文件。这里仿照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>
  1. 实现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;
	}

}
  1. 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);
	}

}
  1. 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();
	}
	
}
  1. 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的名称。
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值