spring 原理1:java 模拟springIOC容器
本篇博客主要是使用java代码模拟spring的IOC容器,实现依赖注入;当然只是模拟spring容器中简单的一点实现原理而已,加深一些自己对spring框架的底层原理的理解;
使用的技术:dom4j xml解析技术 工厂模式 java反射技术
关于工厂模式:主要作用是对象的的解耦,通过容器中的方法获取对象,而不是在需要的类中去 new 对象;针对接口编程,不需要关注具体的实现方式;
如:一个对象:Car 依赖的对象有 Engine Wheel Door
不用工厂模式此时如果需要创建Car,则需要在Car 对象中 创建 Engine Wheel Door 三个对象,这样的弊端是在代码中耦合了太多其他的对象:此时如果Engine 对象和 Wheel对象改变了属性,那么调用者在调用时也需要做修改;如果依赖的对象很多的话,对于调用者是一件很麻烦的事情;
public class Car implements ICar{
private Engine engine;
private Wheel wheel;
private Door door;
public Car(Engine engine, Wheel wheel, Door door) {
super();
this.engine = engine;
this.wheel = wheel;
this.door = door;
}
public static void main(String[] args) {
Engine engine=new Engine();
Wheel wheel=new Wheel();
Door door=new Door();
Car car=new Car(new Engine(), new Wheel(), new Door());
}
}
此时就引入了工厂模式:
Car的工厂类如下所示:
public class Factory implements Ifactory{
@Override
public Car createCar() {
Engine engine=new Engine();
Wheel wheel=new Wheel();
Door door=new Door();
return new Car(engine, wheel, door);
}
}
调用者需要Car的对象的时候只需要调用工厂类的 createCar() 方法即可:这是就算有依赖的类更改了属性或者方法,对于调用方而言可以不做任何更改;
public static void main(String[] args) {
Factory f=new Factory();
ICar car=f.createCar();
}
当然,这样并不完美:试想一个场景:Engine 有 大众的 丰田的 Wheel 也有大众和丰田的 Door 也分为大众和丰田的,现在调用方需要的是大众的Car
那么在工厂类中就需要更改为大众类,如果有上千个品牌,那么工厂类的维护也是一件很痛苦的事,这是引入统一接口,接口的引用指向具体的实现类,具体的实现由调用方指定,这样就减少了代码的耦合;
但是,基于接口的工厂模式还是不完美,这种方式:我需要在工厂类中 new 对象 并且需要通过构造器或者是set方法把需要注入的对象注入进来,此时,试想一个场景:如果你有100个对象需要被其他对象注入,那么这个工厂类则需要维护100 个方法来返回对象;工厂类的维护一件很复杂的任务;
这是可以想到用配置文件来管理这些类的名称,然后在工厂类中通过在配置文件中的类的名称实现类的创建和注入;这样需要增删改工厂类的创建对象则可以通过更改配置文件来实现,这样就方便了很多;
这就是一种比较完美的实现方式:IOC模式;
下面通过java代码来实现ioc模式:
mydoc.xml的配置如下:
<beans>
<bean id="userController" class="bz.beppe.controller.UserController">
<property name="userService" ref="userService"></property>
</bean> <bean id="userService" class="bz.beppe.serviceImpl.UserServiceImpl"></bean> </beans>
userService的接口代码:
public interface UserService {
public void getUser();
}
实现代码如下:
public class UserServiceImpl implements UserService{
@Override
public void getUser() {
System.out.println("i am beppe!!");
}
}
UserController的代码如下
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void getUser(){
userService.getUser();
// System.out.println(user.getName());
}
public void say(){
System.out.println("say something");
}
}
下面模拟spring 的Ioc来实现最基本的依赖注入:
工厂接口如下:BeanFactory 这个接口不做任何的实现,只有一个getBean(String id) 的方法 具体的具体的工厂类需要实现这个接口,并且覆盖相应的方法:
public interface BeanFactory {
public Object getBean(String id);
}
以下为BeanFatory的具体实现类;IOC容器的关键,实现依赖注入;这里用一个Map容器来存储对象,并且可以通过key来获取对象
public class ClassPathXmlApplicationContext implements BeanFactory{
private Map<String,Object> beans=new HashMap<String,Object>(); //创建容器,用来存储需要被IOC容器管理的对象
// 构造该容器时就初始化beans的值
public ClassPathXmlApplicationContext(String filePath){ //在创建工厂对象的时候就将需要被管理的对存放到map中
Document doc = getDocument(filePath); //解析 xml 文件
Element rootElement = doc.getRootElement();
List<Element> beanElements = rootElement.elements();
for (Element beanElement : beanElements) { //获取bean 标签 并且实例化对象
String idStr = beanElement.attributeValue("id");
String classStr=beanElement.attributeValue("class");
System.out.println(idStr+":"+classStr);
try {
Class<?> clazz = Class.forName(classStr);
Object obj = clazz.newInstance();
beans.put(idStr, obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (Element beanElement1 : beanElements) {
List<Element> propertyElements = beanElement1.elements();
for (Element propertyElement : propertyElements) { //获取<bean> 标签下的所有property标签 并且 通过调用set方法来进行注入:关键的方法
Element parentElement=propertyElement.getParent();
Object contoller=getBean(parentElement.attributeValue("id"));
String nameStr = propertyElement.attributeValue("name");
String refStr=propertyElement.attributeValue("ref");
Object service = getBean(refStr);
String methodStr="set"+nameStr.substring(0, 1).toUpperCase()+nameStr.substring(1);
try {
Method method=contoller.getClass().getMethod(methodStr, service.getClass().getInterfaces()[0]);
method.invoke(contoller, service);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Override
public Object getBean(String id) {
// TODO Auto-generated method stub
return beans.get(id);
}
private Document getDocument(String filePath){
try {
// URL url=new URL(filePath);
SAXReader redaer=new SAXReader();
Document doc = redaer.read(filePath);
return doc;
} catch (DocumentException e) {
// TODO Auto-generated catch block
System.out.println("路径不存在");
e.printStackTrace();
}
return null;
}
}
这就是一个简单的spring IOC容器,当然,功能远没有spring IOC那么强大,基本的实现原理是一致的;
spring 原理1:java 模拟springIOC容器的更多相关文章
- java架构之路-(spring源码篇)springIOC容器源码解析(上)
我们这次来叭叭一下Spring的源码,这次博客主要来说说Spring源码,先粗略的撸一遍,下篇博客选几个重点去说,由于过于复杂,我也是看了一点点,我们先来过一遍源码,然后上流程图,最后我们再回头总结一 ...
- 深入理解Spring--动手实现一个简单的SpringIOC容器
接触Spring快半年了,前段时间刚用Spring4+S2H4做完了自己的毕设,但是很明显感觉对Spring尤其是IOC容器的实现原理理解的不到位,说白了,就是仅仅停留在会用的阶段,有一颗想读源码的心 ...
- 深入理解SpringIOC容器
转载来源:[https://www.cnblogs.com/fingerboy/p/5425813.html] 前言: 在逛博客园的时候突然发现一篇关于事务的好文章,说起spring事物就离不开AOP ...
- JAVA模拟Spring实现IoC过程(附源码)
前言:本人大四学生,第一次写博客,如果有写得不好的地方,请大家多多指正 一.IoC(Inversion of Control)反转控制 传统开发都是需要对象就new,但这样做有几个问题: 效率低下,创 ...
- Spring - SpringIOC容器详解
一.什么是Spring IOC: Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想. 在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是 ...
- 转 Spring源码剖析——核心IOC容器原理
Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...
- 转载:把你的精力专注在java,jvm原理,spring原理,mysql锁,事务,多线程,大并发,分布式架构,微服务,以及相关的项目管理等等,这样你的核心竞争力才会越来越高
https://developer.51cto.com/art/202001/608984.htm 把你的精力专注在java,jvm原理,spring原理,mysql锁,事务,多线程,大并发,分布式架 ...
- 浏览器与服务器交互原理以及用java模拟浏览器操作v
浏览器应用服务器JavaPHPApache * 1,在HTTP的WEB应用中, 应用客户端和服务器之间的状态是通过Session来维持的, 而Session的本质就是Cookie, * 简单的讲,当浏 ...
- 【转】Spring学习---SpringIOC容器的初始化过程
[原文]https://www.toutiao.com/i6594400249429623304/ SpringIOC容器的初始化过程 简单来说,IoC容器的初始化是由refresh()方法来启动的, ...
随机推荐
- ubuntu16下用QT5实现对话框应用
ubuntu16下用QT5,实现对话框程序,步骤:生成界面Dialog.ui,将它应用到主程序,通过主程序显示. 一 界面练习 1 Dialog.ui界面生成 在命令行输入:designer 进入界面 ...
- mybatis泛型(一)
mybatis的确很方便,可以随意配置sql语句,并根据参数生成指定的sql,也可以根据查询结果生成指定对象 但是有一点非常恐怖,就是每个数据库表都必须有一个配置,等于在一个系统里做了很多重复的工作, ...
- vscode的环境变量code
vscode的安装路径 本质:vscode的安装路径/Applications/Visual Studio Code.app/Contents/Resources/app/bin 下面有code可执行 ...
- ntp时间同步参考
https://blog.csdn.net/kamereon/article/details/54344114
- Android 查阅博客1_app优化_1大小
Android App Bundle (google play 商店发布应用的话,可自行深入了解下,这里不做介绍) http://mp.weixin.qq.com/s?__biz=MzAwODY4 ...
- cdnbest里如何查看网站是否被缓存
比如开启了强制缓存,如何查看缓存是否生效 本例以firefox浏览器查看,先打开浏览器,按下F12, 然后在浏览器是输入网址访问 如下图响应头里的 x-cache显示 Miss from 就是没有缓 ...
- oracle函数nvl, nvl2, nullif
nvl函数 语法: NVL(表达式1, 表达式2) select nvl(s.name, '未填写') from student s 如果表达式1的值为空, 则显示第二个值, 否则显示原来的值, nv ...
- Python设计模式 - 基础 - 七大基本原则
提倡使用设计模式,主要出发点就是实现代码复用,增加代码的扩展性和可维护性.如何设计出简洁.易懂.灵活.优美的代码结构的确是一门学问,透彻理解并践行如下七大原则通常都能取得基本满意的结果: - 单一职责 ...
- vue.js核心最基本的功能
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统: , text: , text: , text: '随便其它什么人吃的东西' } ] }}) 蔬菜 奶酪 随便其 ...
- tiny4412 --Uboot移植(3) 时钟
开发环境:win10 64位 + VMware12 + Ubuntu14.04 32位 工具链:linaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-g ...