IoC 什么是IoC?
IoC是Inversion of Control(控制反转)的简称,注意它是一个技术思想。描述的是对象创建、管理的事情。
- 传统开发方式:比如类A依赖类B,往往会在类A里面new一个B的对象。
- IoC开发方式:我们不用去new对象,由IoC容器帮我们实例化对象并进行管理。我们需要B对象,就问IoC容器要即可。
IoC的作用:解决了对象之间的耦合问题。
什么是DI?
DI是Dependancy Injection(依赖注入)的简称,指容器会把对象依赖的其他对象注入。比如A对象里声明了一个B的属性,那么就需要容器把B对象注入给A。
什么是AOP?
AOP是 Aspect oriented Programming(?向切?编程)的简称。
文章图片
在上面的代码中,多个方法都出现了相同的代码(可以称之为横切逻辑代码)。这部分代码不仅重复,而且跟业务逻辑没有关系但是混杂在一起。这时AOP出现了,它提供了横向抽取机制,将这部分横切代码和业务逻辑代码分开。
文章图片
AOP的作用:在不改变原有业务逻辑的情况下,增强横切逻辑代码,解耦合。
手写IOC 首先我们看一下在没有Spring之前,我们是怎么开发一个web程序的呢?
文章图片
?
那么针对上面的两个问题,我们如何进行解决呢?
- 我们除了用new实例化对象外,还可以用反射的技术。
- 另外项目中往往有很多对象需要实例化,那么可以使用工厂模式来进行优化。
除此之外,我们还需要一个xml文件,里面来定义对象的全类名(反射需要),如果有依赖,还需要定义类与类之间的依赖关系。
【spring|什么是IOC(教你手撸一个IOC容器)】
核心代码:
public class BeanFactory {private static Map beanMap=new HashMap<>();
static {
InputStream inputStream=BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader=new SAXReader();
try {
Document document = saxReader.read(inputStream);
Element rootElement = document.getRootElement();
List beans = rootElement.selectNodes("//bean");
for (Element element:beans){
String id = element.attributeValue("id");
String clazz = element.attributeValue("class");
Object instance = Class.forName(clazz).newInstance();
beanMap.put(id,instance);
}//实例完后填充对象的依赖
List propertys = rootElement.selectNodes("//property");
for (Element element:propertys){
String name = element.attributeValue("name");
String ref = element.attributeValue("ref");
Element parent = element.getParent();
String parentId = parent.attributeValue("id");
Object instance = beanMap.get(parentId);
Object refInstance = beanMap.get(ref);
Method setMethod = instance.getClass().getDeclaredMethod("set" + name,refInstance.getClass().getInterfaces());
setMethod.invoke(instance,beanMap.get(ref));
}} catch (Exception e) {
e.printStackTrace();
}
}public static Object getBean(String name){
return beanMap.get(name);
}
}
那么接下来我们想要使用对象的时候,就不用new了,而是从beanFactory里面去拿。
这样一个简易的AOP就完成了。
手写AOP实现 我们解决了上面的问题1,那么问题2事务控制如何解决呢?
分析:数据库事务归根结底是Connection的事务,connection.commit()提交事务,connection.rollback()回滚事务。
- 我们是想保证service里的方法里面执行的众多数据库操作要么都成功,要么都失败。
- 同一个service方法里面的dao层必须要使用的是同一个connection,也就是说同一个线程内要是同一个connection,所以可以使用ThreadLocal实现
@Override
public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
//关闭自动提交
connectionUtils.getThreadConn().setAutoCommit(false);
try {
Account from = accountDao.queryAccountByCardNo(fromCardNo);
Account to = accountDao.queryAccountByCardNo(toCardNo);
from.setMoney(from.getMoney()-money);
to.setMoney(to.getMoney()+money);
accountDao.updateAccountByCardNo(to);
int i=10/0;
accountDao.updateAccountByCardNo(from);
//提交事务
connectionUtils.getThreadConn().commit();
} catch (Exception e) {
//回滚事务
connectionUtils.getThreadConn().rollback();
throw e;
}
}
在两次update语句中间手动加了个异常,可以发现数据库两条数据都没变,说明事务控制成功。
但是如果多个方法都需要加事务控制的话,我们需要给多个方法加上下面这一套重复的代码
connectionUtils.getThreadConn().setAutoCommit(false);
try {
//省略部分代码
// -----
//提交事务
connectionUtils.getThreadConn().commit();
} catch (Exception e) {
//回滚事务
connectionUtils.getThreadConn().rollback();
throw e;
}
怎么解决呢?
我们可以通过代理模式给每个方法代理
代码如下:
public class ProxyFactory {private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}public Object getJdkProxy(Object object){
return Proxy.newProxyInstance(ProxyFactory.class.getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object 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();
throw e;
}
return result;
}
});
}}
每个需要加事务的对象,只要调用getJdkProxy方法获取到代理对象,再使用代理对象执行方法,就能实现事务控制了。
使用方法如下:
private ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
private TransferService transferService= (TransferService) proxyFactory.getJdkProxy(BeanFactory.getBean("transferService"));
这样就相当于把横切逻辑代码提取出来了,如果把这套机制抽出来就是AOP的实现了。
如果觉得本文对你有帮助,可以关注一下我公众号,回复关键字【技术】即可各种编程资料以及面试题大礼包!还有更多技术干货文章以及架构资料共享,大家一起学习进步!
文章图片
推荐阅读
- Android|2022-02-26 AndroidR 11 调用文件管理器并返回选中文件的路径
- java|手撸一个Spring IOC容器——渐进式实现
- java|节后上班第一天公司要你用SpringBoot实现万能文件在线预览
- spring|我撸了一个 Spring 容器
- Python|乱世买黄金(用python分析一下最近的股票市场)
- java|撸一个springIoc容器
- java基础|JAVA基础之超详细面向对象程序设计一|CSDN创作打卡
- python|学了这么久的Python,到底是什么水平(用这两个项目就能得到检验)
- 人工智能|名校硕士苦攻5年AI无论文痛苦吐槽,导师放养怎么办()