Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。也是几乎所有Java工作者必须要掌握的框架之一,其优秀的设计思想以及其代码实现上的艺术也是我们需要掌握的。

要学习Spring,除了在我们的项目中使用之外,也需要对它的源码进行研读,但是Spring的实现涵盖的知识很多,在加上其中的类的数量也是非常的多,在我们阅读源码时可能会在几十个类之间穿插阅读,很有可能一不小心就导致思维混乱。

有鉴于此,我这里先对Spring中的几个重要的模块进行一个手动的简易实现,一是熟悉这些模块的原理,同时也是仿造Spring中的结构来对后面阅读源码打下基础。

IOC(Inversion of Control)

Inversion of Control即控制反转,其意思是将我们之前由客户端代码来创建的对象交由IOC容器来进行控制,对象的创建,初始化以及后面的管理都由IOC完成。

IOC的好处

解耦:IOC的出现解决了类与类之间的耦合,我们在Web开发的Servlet时代,如果一个Servlet需要依赖另一个类的某些实现,那么我们需要在当前类对依赖的类进行创建和初始化,如果其他类也依赖了这个类,那也需要进行创建和初始化,而交给了IOC来管理的话,那么在需要的时候只需向IOC进行申请,而不需要重复的创建和初始化。当然,IOC也允许每次都重新创建一个新的对象。

方便与AOP进行配合:AOP也是一个使用十分频繁的功能,通过IOC可以十分方便的与AOP进行配合。

IOC中设计的设计模式

工厂模式。IOC容器来负责创建管理类实例对象,在需要时向IOC进行申请,从IOC中获取。所以IOC容器也称为bean工厂。

工厂模式是一种比较简单易懂的设计模式,这里就不在介绍了,如果有需要的可以看看工厂模式。

IOC的手动实现

Bean定义

IOC的主要的功能便是对Bean进行管理,包括创建、初始化、管理以及销毁的工作。首先我们面对的问题就是我们怎么让IOC能够创建一个Bean?为了创建Bean我们需要提供一些什么?

如何创建Bean

在不手动通过new关键字创建的情况下创建类实例的对象方法有两种:

  • 反射:通过反射的方法可以创建类的实例:clazz.getClass().newInstance();。
  • 工厂模式:工厂模式可以让我们在不接触实例类的情况下创建出实例。
public class PersonFactory{
public Person getPerson(){
return new Person();
}
}

为了创建Bean我们需要提供什么

通过分析上面的两种方法可以轻松得出答案。

对于反射的方式我们仅需提供实例的Class对象。

对于工厂方法我们需要提供的就是创建该类的工厂名(factoryName)和方法名(methodName);

除了创建bean还需要做些什么

IOC容器是对bean的整个生命周期进行管理,除了创建之外还需要对bean进行初始化,以及不需要时对bean进行销毁的工作(如释放资源等)。所以我们还需要提供初始化和销毁等操作。

到这里创建bean需要的基本分析完了,看类图:

Bean工厂

Bean的定义解决了,但是这个bean定义以及创建好的Bean实例放在哪里呢,我们需要一个统一的地方来存放这些东西以方便我们要用的时候方便取。

我们定义一个Bean工厂来存放bean,在需要的时候从bean工厂中取即可,bean工厂对外提供的也仅仅是一个获取bean的方法即可,由于bean的类型不定,所以返回值定位Object。

注册Bean定义

到了现在我们有了创建bean的Bean定义,有了存放和管理bean的Bean工厂,现在需要考虑的是怎么来联系这两个类,我们还需要另外一个接口,接口的功能是让我们能注册和获取bean定义,这里我们通过beanName来区分不同的bean。参考:深究Spring中Bean的生命周期

代码实现

到这里我们实现一个简易的IOC容器的需要的东西基本准备完成了,看下基本类图:

基本代码实现:

DefaultBeanDefinition:

public class DefaultBeanDefinition implements BeanDefinition{

private Class<?> clazz;

private String beanFactoryName;

private String createBeanMethodName;

private String staticCreateBeanMethodName;

private String beanInitMethodName;

private String beanDestoryMethodName;

private boolean isSingleton;

// setter

public void setSingleton(boolean singleton) {
isSingleton = singleton;
}

@Override
public Class<?> getBeanClass() {
return this.clazz;
}

@Override
public String getBeanFactory() {
return this.beanFactoryName;
}

@Override
public String getCreateBeanMethod() {
return this.createBeanMethodName;
}

@Override
public String getStaticCreateBeanMethod() {
return this.staticCreateBeanMethodName;
}

@Override
public String getBeanInitMethodName() {
return this.beanInitMethodName;
}

@Override
public String getBeanDestoryMethodName() {
return this.beanDestoryMethodName;
}

@Override
public String getScope() {
return this.isSingleton?BeanDefinition.SINGLETION :BeanDefinition.PROTOTYPE;
}

@Override
public boolean isSingleton() {
return this.isSingleton;
}

@Override
public boolean isPrototype() {
return !this.isSingleton;
}
}

DefaultBeanFactory:

public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {

private Log log = LogFactory.getLog(this.getClass());

//ConcurrentHashMap应对并发环境
private Map<String, BeanDefinition> bdMap = new ConcurrentHashMap<>();

private Map<String, Object> beanMap = new ConcurrentHashMap<>();

@Override
public void register(BeanDefinition bd, String beanName) {

Assert.assertNotNull("beanName不能为空 beanName", beanName);
Assert.assertNotNull("BeanDefinition不能为空", bd);

if(bdMap.containsKey(beanName)){
log.info("[" + beanName + "]已经存在");
}

if(!bd.validate()){
log.info("BeanDefinition不合法");
}

if(!bdMap.containsKey(beanName)){
bdMap.put(beanName, bd);
}
}

@Override
public boolean containsBeanDefinition(String beanName) {
return bdMap.containsKey(beanName);
}

@Override
public BeanDefinition getBeanDefinition(String beanName) {
if(!bdMap.containsKey(beanName)){
log.info("[" + beanName + "]不存在");
}
return bdMap.get(beanName);
}

public Object doGetBean(String beanName) throws InstantiationException, IllegalAccessException {
if(!beanMap.containsKey(beanName)){
log.info("[" + beanName + "]不存在");
}

Object instance = beanMap.get(beanName);

if(instance != null){
return instance;
}

//不存在则进行创建
if(!this.bdMap.containsKey(beanName)){
log.info("不存在名为:[" + beanName + "]的bean定义");
}

BeanDefinition bd = this.bdMap.get(beanName);

Class<?> beanClass = bd.getBeanClass();

if(beanClass != null){
instance = createBeanByConstruct(beanClass);
if(instance == null){
instance = createBeanByStaticFactoryMethod(bd);
}
}else if(instance == null && StringUtils.isNotBlank(bd.getStaticCreateBeanMethod())){
instance = createBeanByFactoryMethod(bd);
}

this.doInit(bd, instance);

if(instance != null && bd.isSingleton()){
beanMap.put(beanName, instance);
}

return instance;
}

private void doInit(BeanDefinition bd, Object instance) {
Class<?> beanClass = instance.getClass();
if(StringUtils.isNotBlank(bd.getBeanInitMethodName())){
try {
Method method = beanClass.getMethod(bd.getBeanInitMethodName(), null);
method.invoke(instance, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}

/**
* 构造方法创建实例
* @param beanClass
* @return
*/
private Object createBeanByConstruct(Class<?> beanClass) {
Object instance = null;
try {
instance = beanClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}

/**
* 普通工厂方法创建实例
* @param bd
* @return
*/
private Object createBeanByFactoryMethod(BeanDefinition bd) {
Object instance = null;
try {
//获取工厂类
Object factory = doGetBean(bd.getBeanFactory());
//获取创建实例的方法
Method method = factory.getClass().getMethod(bd.getCreateBeanMethod());
//执行方法
instance = method.invoke(factory, null);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}

/**
* 静态方法创建实例
* @param bd
* @return
*/
private Object createBeanByStaticFactoryMethod(BeanDefinition bd) {
Object instance = null;
try {
Class<?> beanClass = bd.getBeanClass();
//获取创建实例的方法
Method method = beanClass.getMethod(bd.getStaticCreateBeanMethod());
instance = method.invoke(beanClass, null);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}

@Override
public Object getBean(String beanName) {
if(!beanMap.containsKey(beanName)){
log.info("[" + beanName + "]不存在");
}
return beanMap.get(beanName);
}

@Override
public void close() throws IOException {
Set<Map.Entry<String, BeanDefinition>> entries = bdMap.entrySet();
for(Map.Entry<String, BeanDefinition> entry: entries){
BeanDefinition value = entry.getValue();
String destoryMethodName = value.getBeanDestoryMethodName();
try {
Method method = value.getBeanClass().getMethod(destoryMethodName, null);
method.invoke(value.getBeanClass(), null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

简单测试一下:实例bean:

public class User {

private String name;

private int age;

//getter setter

public void init(){
System.out.println("init...");
}

public void destory(){
System.out.println("destory...");
}

}

工厂类:

public class TestFactory {
public Object createMethod(){
return new User();
}

public static Object staticCreateMethod(){
return new User();
}
}

测试类:

public class MySpringTest {

static DefaultBeanFactory factory = new DefaultBeanFactory();

@Test
public void test() throws IllegalAccessException, InstantiationException {
DefaultBeanDefinition bd = new DefaultBeanDefinition();
bd.setClazz(User.class);
bd.setSingleton(true);
bd.setBeanFactoryName("TestFactory");
bd.setCreateBeanMethodName("createMethod");
bd.setStaticCreateBeanMethodName("staticCreateMethod");

bd.setBeanInitMethodName("init");

factory.register(bd, "user");

System.out.println(factory.doGetBean("user"));
}
}

小结

一个简易的容器就这样实现了,当然我们这里只是具备了基本的功能,实际上还差的远,比如带参数的bean的实例化等功能。但是IOC的基本原理已经表达出来了,后面我们只需在这个基础上添加新的功能即可。

理解Spring:IOC的原理及手动实现的更多相关文章

  1. 深入理解Spring IOC工作原理

    为什么会出现spring,spring出现解决了什么问题? 1.分析普通多层架构存在的问题 JSP->Servlet->Service->Dao 层与层之间的依赖很强,属于耦合而且是 ...

  2. 通俗化理解Spring3 IoC的原理和主要组件(spring系列知识二总结)

    ♣什么是IoC? ♣通俗化理解IoC原理 ♣IoC好处 ♣工厂模式 ♣IoC的主要组件 ♣IoC的应用实例 ♣附:实例代码 1.什么是IoC(控制反转)? Spring3框架的核心是实现控制反转(Io ...

  3. Spring系列之IOC的原理及手动实现

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 导语 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架.也是几乎所有J ...

  4. Spring IOC设计原理解析:本文乃学习整理参考而来

    Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...

  5. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

  6. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

  7. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  8. spring ioc aop 原理

    spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调 ...

  9. Spring IoC底层原理

    -------------------siwuxie095                                 Spring IoC 底层原理         1.IoC 即 Invers ...

  10. Java工厂模式解耦 —— 理解Spring IOC

    Java工厂模式解耦 -- 理解Spring IOC 最近看到一个很好的思想来理解Spring IOC,故记录下来. 资源获取方式 主动式:(要什么资源都自己创建) 被动式:(资源的获取不是我们创建, ...

随机推荐

  1. Method Overlonding

    The method overloading is using one single method name with different parameters to created differen ...

  2. web.xml 基本配置(SSM maven项目)

    <web-app> <display-name>Archetype Created Web Application</display-name> <!--we ...

  3. JAVA8 lambda表达式权威教程!

    Java 8新特性----Stream流 jdk8是Java 语言开发的一个主要版本,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等等.今天就重点介 ...

  4. 迷失在Mysql的锁世界~

    1.饮料 这是一杯饮料. 这是3杯饮料,每杯饮料的味道各不相同. 但是人类并不称呼[饮料]为[饮料],而是称呼[饮料]为[记录]. 2.红章鱼 这个红色的,长的像章鱼的家伙,我们就叫它红章鱼~ 红章鱼 ...

  5. java面试一日一题:java中一个对象实例的结构是什么样子的

    问题:请讲下在java程序运行时一个对象实例的数据结构是什么样子的 分析:该问题主要考察对java中对象的理解,在程序运行过程中一个对象实例是以什么样的形式存在的 回答要点: 主要从以下几点去考虑, ...

  6. Java 正则表达式实例操作

    Regular Expression正则表达式,简称RegExp,常规通用的表达式,在多个开发语言中都有它的实现,可以通过正则表达式来快速的检索.匹配.查找.替换字符串中的文本. 简单实例 匹配网址 ...

  7. 【海通国际】Joe Lowry(Mr. Lithium)谈全球电池原材料供应危机

    [海通国际]Joe Lowry(Mr. Lithium)谈全球电池原材料供应危机 环球锂业公司(Global Lithium)总裁Joe Lowry日前接受了欧洲锰业Euro Manganese的邀请 ...

  8. 攻防世界(八)web2

    攻防世界系列:web2 1.代码审计  知识补充: strrev(string):反转字符串 strlen(string):字符串长度 substr(string,start,length):截取字符 ...

  9. # useradd -u 700 -g users vbird2

    [root@linux ~]# ls -l /homedrwxr-xr-x 3 vbird1 vbird1 4096 Aug 30 17:33 vbird1[root@linux ~]# grep v ...

  10. shell进阶之tree、pstree、lsof命令详解

    一.tree命令详解: 主要功能是创建文件列表,将所有文件以树的形式列出来 -a 显示所有文件和目录. -A 使用ASNI绘图字符显示树状图而非以ASCII字符组合. -C 在文件和目录清单加上色彩, ...