自己实现简单Spring Ioc
IoC则是一种 软件设计模式,简单来说Spring通过工厂+反射来实现IoC。
原理简单说明:
其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这bean。
通俗来讲就如同婚姻介绍所,只需要告诉它找个什么样的女朋友,然后婚介就会按照我们的要求,提供一个mm,如果婚介给我们的人选不符合要求,我们就会抛出异常。
简单实现:
1.需要引用maven依赖:
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1.3</version>
</dependency>
2.beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="user" class="com.example.domain.User" />
<bean id="userDAO" class="com.example.dao.impl.UserDAOImpl" />
<bean id="userService" class="com.example.service.UserService">
<property name="userDAO" bean="userDAO" />
</bean>
</beans>
3.BeanFactory
package com.example.ioc;
public interface BeanFactory {
Object getBean(String name);
}
4.ClassPathXmlApplicationContext:读取xml文件内容,并创建对象及对象关系(使用setter方式)
package com.example.ioc;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans = new HashMap<String, Object>();
public ClassPathXmlApplicationContext() throws Exception {
SAXBuilder sb = new SAXBuilder();
// 构造文档对象
Document doc = sb.build(ClassPathXmlApplicationContext.class
.getClassLoader().getResourceAsStream("beans.xml"));
// 获取根元素
Element root = doc.getRootElement();
// 取到根元素所有元素
List list = root.getChildren();
setBeans(list);
}
//设置Bean
private void setBeans(List list) throws Exception {
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String id = element.getAttributeValue("id");
//取得class子元素
String clzss = element.getAttributeValue("class");
//通过反射进行实例化
Object o = Class.forName(clzss).newInstance();
beans.put(id, o);
setProperty(element, o);
}
}
//获取property进行依赖注入
private void setProperty(Element element, Object o) throws Exception {
for (Element property : (List<Element>) element.getChildren("property")) {
String name = property.getAttributeValue("name");
String bean = property.getAttributeValue("bean");
//从beans.xml中根据id取到类的对象
Object beanObj = this.getBean(bean);
System.out.println(beanObj);//com.example.dao.impl.UserDAOImpl@2f4d3709
//组成setXXX方法名
String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
// 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中
Method m = o.getClass().getMethod(methodName, beanObj.getClass().getInterfaces()[0]);
m.invoke(o, beanObj);
}
}
@Override
public Object getBean(String name) {
return beans.get(name);
}
}
以上为核心代码,当然在实际情况中,这一块要复杂的多, 例如:可以一个bean引用另一个bean,还可以有多个配置文件、通过多种方式载入配置文件等等,不过原理还是采用Java的反射机制。
实现的效果为:
Service service=(Service)beans.get("userService");
Dao dao = (Dao)beans.get("userDAO");
//依赖注入,Service实现依赖dao的实现
service.setDao(dao);
5.User:实体类
package com.example.domain;
public class User {
private String userName;
private String password;
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(this.userName);
sb.append(this.password);
return sb.toString();
}
}
6.UserDAO
package com.example.dao;
import com.example.domain.User;
public interface UserDAO {
void save(User u);
void delete();
}
7.UserDAOImpl
package com.example.dao.impl;
import com.example.dao.UserDAO;
import com.example.domain.User;
public class UserDAOImpl implements UserDAO {
@Override
public void save(User u) {
System.out.println("User:" + u.toString());
}
@Override
public void delete() {
System.out.println("delete User");
}
}
8.UserService
package com.example.service;
import com.example.dao.UserDAO;
import com.example.domain.User;
public class UserService {
private UserDAO userDAO;
public void addUser(User u) {
this.userDAO.save(u);
}
/**
* @return the userDAO
*/
public UserDAO getUserDAO() {
return userDAO;
}
/**
* @param userDAO the userDAO to set
*/
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
9.测试:
package com.example.ioc;
import com.example.domain.User;
import com.example.service.UserService;
public class RunIoc {
public static void main(String[] args) throws Exception {
BeanFactory factory = new ClassPathXmlApplicationContext();
//通过工厂直接获取
UserService userService = (UserService) factory.getBean("userService");
//其实User也可以从工厂中获得
User u = (User) factory.getBean("user");
//User u = new User();
u.setUserName("tom");
u.setPassword("123456");
userService.addUser(u);//打印结果tom123456
}
}
小结
上文仅仅是简单地模拟了spring的IOC的实现,虽然只是完成了spring中依赖注入的一小部分,但还是很好地展现了Java反射机制在spring中的应用
自己实现简单Spring Ioc的更多相关文章
- Spring IOC 方式结合TESTGN测试用例,测试简单java的命令模式
java命令模式: 可以命令("请求")封装成一个对象,一个命令对象通过在特定的接收着上绑定一组动作来封装一个请求.命令对象直接把执行动作和接收者包进对象中,只对外暴露出执行方法的 ...
- 1.Spring IoC简单例子
Spring IoC简单例子 1.IHelloMessage.java package com.tony.spring.chapter01; public interface IHelloMessag ...
- 比Spring简单的IoC容器
比Spring简单的IoC容器 Spring 虽然比起EJB轻量了许多,但是因为它需要兼容许多不同的类库,导致现在Spring还是相当的庞大的,动不动就上40MB的jar包, 而且想要理解Spring ...
- 实现IOC功能的简单Spring框架
需求分析 设计一个含有IOC的简单Spring,要求含有对象注册.对象管理以及暴露给外部的获取对象功能. 项目设计 对于注册的对象用一个类BeanInfo来描述其信息,包括对象标识.全类名以及属性名与 ...
- Spring IOC 源码简单分析 03 - 循环引用
### 准备 ## 目标 了解 Spring 如何处理循环引用 ##测试代码 gordon.study.spring.ioc.IOC03_CircularReference.java ioc03. ...
- Spring IOC 源码简单分析 02 - Bean Reference
### 准备 ## 目标 了解 bean reference 装配的流程 ##测试代码 gordon.study.spring.ioc.IOC02_BeanReference.java ioc02 ...
- Spring IOC 的简单使用
Spring IOC (Inversion Of Control反转控制容器 一.对于IOC容器的简单理解 在java开发中将程序中的对象交给容器管理,而不是在对象的内部管理. 那么两个简单的问题去分 ...
- Spring IOC的简单实现
简单的说,Spring就是通过工厂+反射将我们的bean放到它的容器中的,当我们想用某个bean的时候,只需要调用getBean("beanID")方法即可. 原理简单说明: Sp ...
- 手写一个最简单的IOC容器,从而了解spring的核心原理
从事开发工作多年,spring源码没有特意去看过.但是相关技术原理倒是背了不少,毕竟面试的那关还是得过啊! 正所谓面试造火箭,工作拧螺丝.下面实现一个最简单的ioc容器,供大家参考. 1.最终结果 2 ...
随机推荐
- Scrapy框架爬虫初探——中关村在线手机参数数据爬取
关于Scrapy如何安装部署的文章已经相当多了,但是网上实战的例子还不是很多,近来正好在学习该爬虫框架,就简单写了个Spider Demo来实践.作为硬件数码控,我选择了经常光顾的中关村在线的手机页面 ...
- Spark踩坑记——Spark Streaming+Kafka
[TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...
- 【趣事】用 JavaScript 对抗 DDOS 攻击
继续趣事分享. 上回聊到了大学里用一根网线发起攻击,今天接着往后讲. 不过这次讲的正好相反 -- 不是攻击,而是防御.一个奇葩防火墙的开发经历. 第二学期大家都带了电脑,于是可以用更高端的方法断网了. ...
- 百度 flash html5自切换 多文件异步上传控件webuploader基本用法
双核浏览器下在chrome内核中使用uploadify总有302问题,也不知道如何修复,之所以喜欢360浏览器是因为帮客户控制渲染内核: 若页面需默认用极速核,增加标签:<meta name=& ...
- Android-armebi-v7a、arm64-v8a、armebi的坑
先来一波扫盲: armeabi:针对普通的或旧的arm v5 cpu armeabi-v7a:针对有浮点运算或高级扩展功能的arm v7 cpu(32位ARM设备) arm64-v8a:64位ARM设 ...
- HTML文档头部
前面的话 在声明文档类型之后,HTML文档的下一部分为<html>标签,告知浏览器应将括在<html>...</html>内的所有内容解析为HTML.然后是HT ...
- UWP开发必备:常用数据列表控件汇总比较
今天是想通过实例将UWP开发常用的数据列表做汇总比较,作为以后项目开发参考.UWP开发必备知识点总结请参照[UWP开发必备以及常用知识点总结]. 本次主要讨论以下控件: GridView:用于显示数据 ...
- JS魔法堂:不完全国际化&本地化手册 之 理論篇
前言 最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...
- 游走 bzoj 3143
游走(2s 128MB)walk [问题描述] [输入格式] [输出格式] [样例输入] 3 3 2 3 1 2 1 3 [样例输出] 3.333 [样例说明] 题解: 主要算法:贪心:高斯消元: 题 ...
- 海康网络摄像机YV12转换为BGR,由opencv Mat显示 (转)
我使用的是海康DS-2CD852MF-E, 200万,网络摄像机,已经比较老了,不过SDK在海康官网下载的,开发流程都差不多. 海康摄像机回调解码后的视频数据格式为YV12,顺便说一下YV12的数据格 ...