美文网首页
什么是IOC?教你手撸一个IOC容器

什么是IOC?教你手撸一个IOC容器

作者: Fightover | 来源:发表于2022-01-18 13:46 被阅读0次

IoC

什么是IoC?

IoC是Inversion of Control(控制反转)的简称,注意它是一个技术思想。描述的是对象创建、管理的事情。

传统开发方式:比如类A依赖类B,往往会在类A里面new一个B的对象。

IoC开发方式:我们不用去new对象,由IoC容器帮我们实例化对象并进行管理。我们需要B对象,就问IoC容器要即可。

控制反转就是说将对象创建、管理的权力交给了外部环境(IoC容器)。

IoC的作用:解决了对象之间的耦合问题。

什么是DI?

DI是Dependancy Injection(依赖注入)的简称,指容器会把对象依赖的其他对象注入。比如A对象里声明了一个B的属性,那么就需要容器把B对象注入给A。

什么是AOP?

AOP是 Aspect oriented Programming(⾯向切⾯编程)的简称。

在上面的代码中,多个方法都出现了相同的代码(可以称之为横切逻辑代码)。这部分代码不仅重复,而且跟业务逻辑没有关系但是混杂在一起。这时AOP出现了,它提供了横向抽取机制,将这部分横切代码和业务逻辑代码分开。

AOP的作用:在不改变原有业务逻辑的情况下,增强横切逻辑代码,解耦合。

手写IOC

首先我们看一下在没有Spring之前,我们是怎么开发一个web程序的呢?

那么针对上面的两个问题,我们如何进行解决呢?

我们除了用new实例化对象外,还可以用反射的技术。

另外项目中往往有很多对象需要实例化,那么可以使用工厂模式来进行优化。

综上,我们可以用工厂模式+反射技术把对象都实例化好,放在一个map里面,如果需要某个对象,就可以直接从这个map里面取。

除此之外,我们还需要一个xml文件,里面来定义对象的全类名(反射需要),如果有依赖,还需要定义类与类之间的依赖关系。

<!--这里的name默认为set+name就是方法名-->

核心代码:

publicclassBeanFactory {privatestaticMap beanMap=newHashMap<>();static{        InputStream inputStream=BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");        SAXReader saxReader=newSAXReader();try{            Documentdocument= saxReader.read(inputStream);            Element rootElement =document.getRootElement();            List beans = rootElement.selectNodes("//bean");for(Element element:beans){Stringid = element.attributeValue("id");Stringclazz = element.attributeValue("class");Objectinstance = Class.forName(clazz).newInstance();                beanMap.put(id,instance);            }//实例完后填充对象的依赖List propertys = rootElement.selectNodes("//property");for(Element element:propertys){Stringname = element.attributeValue("name");Stringref = element.attributeValue("ref");                Element parent = element.getParent();StringparentId = parent.attributeValue("id");Objectinstance = beanMap.get(parentId);ObjectrefInstance = beanMap.get(ref);                Method setMethod = instance.getClass().getDeclaredMethod("set"+ name,refInstance.getClass().getInterfaces());                setMethod.invoke(instance,beanMap.get(ref));            }        }catch(Exception e) {            e.printStackTrace();        }    }publicstaticObjectgetBean(Stringname){returnbeanMap.get(name);    }}

那么接下来我们想要使用对象的时候,就不用new了,而是从beanFactory里面去拿。

这样一个简易的AOP就完成了。

手写AOP实现

我们解决了上面的问题1,那么问题2事务控制如何解决呢?

分析:数据库事务归根结底是Connection的事务,connection.commit()提交事务,connection.rollback()回滚事务。

我们是想保证service里的方法里面执行的众多数据库操作要么都成功,要么都失败。

同一个service方法里面的dao层必须要使用的是同一个connection,也就是说同一个线程内要是同一个connection,所以可以使用ThreadLocal实现

改造完成:

@Overridepublicvoidtransfer(String fromCardNo, String toCardNo,intmoney) throws Exception{//关闭自动提交connectionUtils.getThreadConn().setAutoCommit(false);try{            Accountfrom= accountDao.queryAccountByCardNo(fromCardNo);            Account to = accountDao.queryAccountByCardNo(toCardNo);from.setMoney(from.getMoney()-money);            to.setMoney(to.getMoney()+money);            accountDao.updateAccountByCardNo(to);inti=10/0;            accountDao.updateAccountByCardNo(from);//提交事务connectionUtils.getThreadConn().commit();        }catch(Exception e) {//回滚事务            connectionUtils.getThreadConn().rollback();throwe;        }    }

在两次update语句中间手动加了个异常,可以发现数据库两条数据都没变,说明事务控制成功。

但是如果多个方法都需要加事务控制的话,我们需要给多个方法加上下面这一套重复的代码

connectionUtils.getThreadConn().setAutoCommit(false);try{//省略部分代码// -----//提交事务connectionUtils.getThreadConn().commit();}catch(Exception e) {//回滚事务connectionUtils.getThreadConn().rollback();throwe;}

怎么解决呢?

我们可以通过代理模式给每个方法代理

代码如下:

publicclassProxyFactory{privateConnectionUtils connectionUtils;publicvoid setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;    }publicObject getJdkProxy(Objectobject){returnProxy.newProxyInstance(ProxyFactory.class.getClassLoader(),object.getClass().getInterfaces(), new InvocationHandler() {@OverridepublicObject invoke(Object proxy, Method method, Object[] args) throws Throwable {//关闭自动提交connectionUtils.getThreadConn().setAutoCommit(false);                Object result;try{                    result= method.invoke(object,args);//提交事务connectionUtils.getThreadConn().commit();                }catch(Exception e) {//回滚事务connectionUtils.getThreadConn().rollback();throwe;                }returnresult;            }        });    }}

每个需要加事务的对象,只要调用getJdkProxy方法获取到代理对象,再使用代理对象执行方法,就能实现事务控制了。

使用方法如下:

privateProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");privateTransferService transferService= (TransferService) proxyFactory.getJdkProxy(BeanFactory.getBean("transferService"));

这样就相当于把横切逻辑代码提取出来了,如果把这套机制抽出来就是AOP的实现了。

相关文章

  • 什么是IOC?教你手撸一个IOC容器

    IoC 什么是IoC? IoC是Inversion of Control(控制反转)的简称,注意它是一个技术思想。...

  • 2.IOC原理分析

    要想使用Spring IOC,必须要创建Spring IOC容器 ? 什么是IOC容器? 所谓的IoC容器就是指的...

  • SpringMVC

    一、Spring IOC容器原理 ioc容器是什么 ioc容器是一个很大的map对象,是单例的,只有一个map,m...

  • spring整理

    ioc 什么是ioc? 1.IOC是Inversion of Control的缩写,翻译为控制反转。ioc是容器,...

  • Spring 面试总结(值得收藏)

    (1)说一说什么是IOC spring是一个ioc容器,容器就是放数据的,ioc容器实际上就是个map(key,v...

  • 1、IOC(容器)&DI(依赖注入)

    1、什么是IOC?ioc是spring容器,ioc是spring框架的核心,ioc可以分为两类,BeanFacto...

  • Spring学习

    IOC (接口) 1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂; 2、Spring提供的IOC容器...

  • Spring源码解读,认识Spring IOC容器

    知识要点: 什么是Spring IoC容器 什么是IoC 什么是依赖倒置 为什么需要Spring IoC 什么是S...

  • spring IOC容器管理必须知道这些操作——基于XML方式

    Spring——IOC(控制反转) 一、IOC容器 ​ 1、什么是IOC(控制反转) ​ a)把对象创建和对象之间...

  • 2018-06-08

    IOC 容器 IOC容器和beans Spring实现了IOC (Inversion of Control)(控制...

网友评论

      本文标题:什么是IOC?教你手撸一个IOC容器

      本文链接:https://www.haomeiwen.com/subject/ixykhrtx.html