spring进阶
2015-09-28 10:06
726 查看
最近一直在和容器打交道,甚至前面的博文,我们也介绍了Spring的IoC的原理以及源码,但是回头看看,duang~ duang~的,还是深了,不够通俗易懂,不够深入浅出。由于以上原因吧,从这篇博客开始,我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC的原理和源码。
相信大家对容器并不陌生,它是生活中非常常见的物品,容器用来包装和装载物品的贮存器(如箱、罐、坛等等),但是在编程中什么容器呢?我们先看一下百科的解释:
---------------------------------------------------------------------------------------------------------------------------------------------------------
容器可以管理对象的生命周期、对象与对象之间的依赖关系,您可以使用一个配置文件(通常是XML),在上面定义好对象的名称、如何产生(Prototype 方式或Singleton 方式)、哪个对象产生之后必须设定成为某个对象的属性等,在启动容器之后,所有的对象都可以直接取用,不用编写任何一行程序代码来产生对象,或是建立对象与对象之间的依赖关系。
---------------------------------------------------------------------------------------------------------------------------------------------------------
看见上面的解释,第一感觉就是什么玩意?说白了,容器就是一个专门用来管理对象的模块。它负责创建对象,管理对象的依赖关系,管理对象的生命周期等等,类似这样的模块就叫容器。
运行在容器中的对象也称为组件,它们必须遵循容器定义的规范。
我们理解了容器之后,下面我们从一个简单的实例开始。先看一下代码:
Service层:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
public interface Service {
public void serviceMethod();
}
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import com.tgb.container.dao.Dao;
import com.tgb.container.dao.impl.Dao4MySqlImpl;
import com.tgb.container.service.Service;
public class ServiceImpl implements Service {
//实例化Dao实现
private Dao dao = new Dao4MySqlImpl();
@Override
public void serviceMethod() {
//调用Dao实现的方法
dao.daoMethod();
}
}
Dao层:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
public interface Dao {
public void daoMethod();
}
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import com.tgb.container.dao.Dao;
public class Dao4MySqlImpl implements Dao {
public void daoMethod(){
System.out.println("Dao4MySqlImpl.daoMethod()");
}
}
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import com.tgb.container.dao.Dao;
public class Dao4OracleImpl implements Dao {
public void daoMethod(){
System.out.println("Dao4OracleImpl.daoMethod()");
}
}
客户端:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import com.tgb.container.service.Service;
import com.tgb.container.service.impl.ServiceImpl;
public class Client {
public static void main(String[] args) {
//实例化Service实现
Service service = new ServiceImpl();
//调用Service实现的方法
service.serviceMethod();
}
}
这段代码的运行结果,大家一眼就能看出来,如下:
Dao4MySqlImpl.daoMethod()
UML类图如下:
![](https://img-blog.csdn.net/20150308161543563?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaml1cWl5dWxpYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
从上图我们可以发现,ServiceImpl不仅依赖Dao层接口,而且还依赖Dao层实现,显然违背了面向对象的基本设计原则,依赖倒转原则:抽象不应该依赖细节,细节应该依赖与抽象,说白了,就是针对接口编程,不要对实现编程。
下面我们使用容器来将依赖实现的关系去掉。
Container类:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import java.util.HashMap;
import java.util.Map;
import com.tgb.container.dao.Dao;
import com.tgb.container.dao.impl.Dao4MySqlImpl;
import com.tgb.container.service.Service;
import com.tgb.container.service.impl.ServiceImpl;
public class Container {
//定义一个map结构的对象
private static Map<String, Object> components;
private Container() {
}
/**
* 初始化容器
*/
public static synchronized void init() {
if (components == null) {
components = new HashMap<String, Object>();
//写一个读配置文件的类,根据读取的配置文件,反射对应的类
//反射好类后进行 依赖管理,往对应的属性上注入相应的类
//客户端创建新类的时候把容器创建好的类付给新类
Dao dao4Mysql = new Dao4MySqlImpl();
components.put("dao4Mysql", dao4Mysql);
Service service = new ServiceImpl();
components.put("service", service);
}
}
/**
* 查找组件
*
* @param id
* @return
*/
public static Object getComponent(String id) {
return components.get(id);
}
}
修改ServiceImpl类:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import com.tgb.container.Container;
import com.tgb.container.dao.Dao;
import com.tgb.container.service.Service;
public class ServiceImpl implements Service {
//从容器查找响应的对象
private Dao dao = (Dao) Container.getComponent("dao4Mysql");
@Override
public void serviceMethod() {
dao.daoMethod();
}
}
客户端:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
import com.tgb.container.Container;
import com.tgb.container.service.Service;
public class Client {
public static void main(String[] args) {
//容器初始化,这个可以用filter完成,只需在整个项目中初始化一次
Container.init();
//从容器中查找接口
Service service =(Service)Container.getComponent("service");
//调用Service实现的方法
service.serviceMethod();
}
}
此时的UML类图如下:
![](https://img-blog.csdn.net/20150308161615777?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaml1cWl5dWxpYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
对比两张类图,我们可以发现,容器给我们带来了优点,同时也带来了缺点。
优点:
此时的Service层不再依赖Dao层实现,而把这种对实现的依赖交给了容器。
缺点:
但是我们却发现,ServiceImpl依赖了Container容器类,使得组件不能脱离容器独立存在,显然,这是一种“侵入式”的管理。
容器
相信大家对容器并不陌生,它是生活中非常常见的物品,容器用来包装和装载物品的贮存器(如箱、罐、坛等等),但是在编程中什么容器呢?我们先看一下百科的解释:
---------------------------------------------------------------------------------------------------------------------------------------------------------
容器可以管理对象的生命周期、对象与对象之间的依赖关系,您可以使用一个配置文件(通常是XML),在上面定义好对象的名称、如何产生(Prototype 方式或Singleton 方式)、哪个对象产生之后必须设定成为某个对象的属性等,在启动容器之后,所有的对象都可以直接取用,不用编写任何一行程序代码来产生对象,或是建立对象与对象之间的依赖关系。
---------------------------------------------------------------------------------------------------------------------------------------------------------
看见上面的解释,第一感觉就是什么玩意?说白了,容器就是一个专门用来管理对象的模块。它负责创建对象,管理对象的依赖关系,管理对象的生命周期等等,类似这样的模块就叫容器。
运行在容器中的对象也称为组件,它们必须遵循容器定义的规范。
普通实现
我们理解了容器之后,下面我们从一个简单的实例开始。先看一下代码:
Service层:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
public interface Service {
public void serviceMethod();
}
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import com.tgb.container.dao.Dao;
import com.tgb.container.dao.impl.Dao4MySqlImpl;
import com.tgb.container.service.Service;
public class ServiceImpl implements Service {
//实例化Dao实现
private Dao dao = new Dao4MySqlImpl();
@Override
public void serviceMethod() {
//调用Dao实现的方法
dao.daoMethod();
}
}
Dao层:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
public interface Dao {
public void daoMethod();
}
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import com.tgb.container.dao.Dao;
public class Dao4MySqlImpl implements Dao {
public void daoMethod(){
System.out.println("Dao4MySqlImpl.daoMethod()");
}
}
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import com.tgb.container.dao.Dao;
public class Dao4OracleImpl implements Dao {
public void daoMethod(){
System.out.println("Dao4OracleImpl.daoMethod()");
}
}
客户端:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import com.tgb.container.service.Service;
import com.tgb.container.service.impl.ServiceImpl;
public class Client {
public static void main(String[] args) {
//实例化Service实现
Service service = new ServiceImpl();
//调用Service实现的方法
service.serviceMethod();
}
}
这段代码的运行结果,大家一眼就能看出来,如下:
Dao4MySqlImpl.daoMethod()
UML类图如下:
从上图我们可以发现,ServiceImpl不仅依赖Dao层接口,而且还依赖Dao层实现,显然违背了面向对象的基本设计原则,依赖倒转原则:抽象不应该依赖细节,细节应该依赖与抽象,说白了,就是针对接口编程,不要对实现编程。
借助容器
下面我们使用容器来将依赖实现的关系去掉。
Container类:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import java.util.HashMap;
import java.util.Map;
import com.tgb.container.dao.Dao;
import com.tgb.container.dao.impl.Dao4MySqlImpl;
import com.tgb.container.service.Service;
import com.tgb.container.service.impl.ServiceImpl;
public class Container {
//定义一个map结构的对象
private static Map<String, Object> components;
private Container() {
}
/**
* 初始化容器
*/
public static synchronized void init() {
if (components == null) {
components = new HashMap<String, Object>();
//写一个读配置文件的类,根据读取的配置文件,反射对应的类
//反射好类后进行 依赖管理,往对应的属性上注入相应的类
//客户端创建新类的时候把容器创建好的类付给新类
Dao dao4Mysql = new Dao4MySqlImpl();
components.put("dao4Mysql", dao4Mysql);
Service service = new ServiceImpl();
components.put("service", service);
}
}
/**
* 查找组件
*
* @param id
* @return
*/
public static Object getComponent(String id) {
return components.get(id);
}
}
修改ServiceImpl类:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import com.tgb.container.Container;
import com.tgb.container.dao.Dao;
import com.tgb.container.service.Service;
public class ServiceImpl implements Service {
//从容器查找响应的对象
private Dao dao = (Dao) Container.getComponent("dao4Mysql");
@Override
public void serviceMethod() {
dao.daoMethod();
}
}
客户端:
[java] view
plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
import com.tgb.container.Container;
import com.tgb.container.service.Service;
public class Client {
public static void main(String[] args) {
//容器初始化,这个可以用filter完成,只需在整个项目中初始化一次
Container.init();
//从容器中查找接口
Service service =(Service)Container.getComponent("service");
//调用Service实现的方法
service.serviceMethod();
}
}
此时的UML类图如下:
对比两张类图,我们可以发现,容器给我们带来了优点,同时也带来了缺点。
优点:
此时的Service层不再依赖Dao层实现,而把这种对实现的依赖交给了容器。
缺点:
但是我们却发现,ServiceImpl依赖了Container容器类,使得组件不能脱离容器独立存在,显然,这是一种“侵入式”的管理。
相关文章推荐
- Mybatis 接口编程+Spring注解版加载容器
- 常用加密算法的Java实现总结
- JavaSE--- 设计模式、JDK5.0新特性、JDK7.0新特性
- easyui ajax请求获取SpringMVC @ResponseBody返回Json数据
- 关于如何解决Eclipse闪退进不去的问题
- java图片处理——多张图片合成一张Gif图片并播放或Gif拆分成多张图片
- Spring MVC URL 路径映射
- Spring mvc JS上传文件
- Spring Batch Tutorial
- eclipse 如何将maven target目录排除在搜索结果之外?
- JDK、J2EE、J2SE、J2ME的区别
- Spring xml中进行autowired的方式
- 双向链表(LinkedList) java实现
- JAVA进程占用高内存原因分析与优化方法
- JAVA基础应用——连接Sql server
- 搭建Spring MVC环境进行简单的增、删、改、查。
- 【Java EE 学习 49 上】【Spring学习第一天】【基本配置】
- Mac OS X 下的JDK路径
- java的23种模式
- eclipse 启动时异常处理