# myspring
**Repository Path**: mr_sen/myspring
## Basic Information
- **Project Name**: myspring
- **Description**: 自定义ioc框架
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-09-20
- **Last Updated**: 2021-09-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 自定义ioc容器
## 步骤流程
### 1. 要定义一个ioc的配置文件
```xml
```
### 2.创建BeanFactory类,来解析xml文件并创建对象保存到ioc中,同时把暴露ioc对象访问接口
```java
package com.lagou.factory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 张在森
* @create 22:54
*
* 工厂类,用于生产(通过反射的方式)对象
*
* 完成的工作
* 1. 读取并解析xml文件,同时用反射方式创建对象,并把对象放到map集合中
* 2. 对外提供获取对象实例的接口
*/
public class BeanFactory {
private static Map beans = new HashMap<>();
static {
// step1 :读取并解析xml,并将创建的对象放到map中年
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
System.out.println("ioc 被实例化.....");
/*
* */
Document document = saxReader.read(resourceAsStream);
Element rootElement = document.getRootElement();
/*
* xpath :使用路径表达式来选取xml文档中的节点
* 常用路径表达式:
* nodename: 选取此节点的所有子节点
* / : 从跟地点选取
* //: 从当前节点下选择节点,不考虑他们的位置
* . : 选取当前节点
* .. : 选取当前节点的父节点
* @ : 选取属性
* */
List list = rootElement.selectNodes("//bean");
//region == 使用for循环进行遍历
// for (Element bean : list) {
// String aClass = bean.attributeValue("class");
// String id = bean.attributeValue("id");
// Class> clazz = Class.forName(aClass);
// Object o = clazz.newInstance();
// beans.put(id, o);
//
// // beans.put(id, o);
// }
// endregion
list.forEach(bean -> {
String aClass = bean.attributeValue("class");
String id = bean.attributeValue("id");
try {
Class> clazz = Class.forName(aClass);
Object o = clazz.newInstance();
beans.put(id, o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
// step2:暴露访问对象
public static Object getBean(String id) {
return beans.get(id);
}
public static Object getBean(Class type) {
for (Map.Entry entry : beans.entrySet()) {
String id = entry.getKey();
Object obj = entry.getValue();
Class> aClass = obj.getClass();
// aClass.getTypeName()
if (obj.getClass().getTypeName().equals(type.getTypeName())) {
return obj;
}
}
throw new RuntimeException("未查到指定类型的bean");
}
}
```
## 题外话
dom4j 和xpath的使用
- 依赖
```xml
dom4j
dom4j
1.6.1
jaxen
jaxen
1.1.6
```
- xpath的使用
xpath :使用路径表达式来选取xml文档中的节点
常用路径表达式:
nodename: 选取此节点的所有子节点
/ : 从跟地点选取
//: 从当前节点下选择节点,不考虑他们的位置
. : 选取当前节点
.. : 选取当前节点的父节点
@ : 选取属性
## 待解决
使用foreach 等方法, lamda表达式中如何使用当前方法中的局部变量
## 升级,service层中依赖dao层的对象使用setter方法注入
修改BeanFactory中初始化方法
```java
package com.lagou.factory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 张在森
* @create 22:54
*
* 工厂类,用于生产(通过反射的方式)对象
*
* 完成的工作
* 1. 读取并解析xml文件,同时用反射方式创建对象,并把对象放到map集合中
* 2. 对外提供获取对象实例的接口
*/
public class BeanFactory {
private static Map beans = new HashMap<>();
static {
// step1 :读取并解析xml,并将创建的对象放到map中年
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
System.out.println("ioc 被实例化.....");
/*
* */
Document document = saxReader.read(resourceAsStream);
Element rootElement = document.getRootElement();
/*
* xpath :使用路径表达式来选取xml文档中的节点
* 常用路径表达式:
* nodename: 选取此节点的所有子节点
* / : 从跟地点选取
* //: 从当前节点下选择节点,不考虑他们的位置
* . : 选取当前节点
* .. : 选取当前节点的父节点
* @ : 选取属性
* */
List list = rootElement.selectNodes("//bean");
//region == 使用for循环进行遍历
// for (Element bean : list) {
// String aClass = bean.attributeValue("class");
// String id = bean.attributeValue("id");
// Class> clazz = Class.forName(aClass);
// Object o = clazz.newInstance();
// beans.put(id, o);
//
// // beans.put(id, o);
// }
// endregion
list.forEach(bean -> {
String aClass = bean.attributeValue("class");
String id = bean.attributeValue("id");
try {
Class> clazz = Class.forName(aClass);
Object o = clazz.newInstance();
beans.put(id, o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
// 实例化完成后维护对象的依赖关系,检测那些对象需要传值
List properties = rootElement.selectNodes("//property");
properties.forEach(property -> {
System.out.println("bean 依赖开始装配.....");
/*
*/
try {
// 依赖的信息
String name = property.attributeValue("name");
String ref = property.attributeValue("ref");
// Class> properyClass = Class.forName(ref);
Object propertyObj = getBean(ref);
// 父对象的信息
Element parent = property.getParent();
String id = parent.attributeValue("id");
Object o = beans.get(id);
Class> aClass = o.getClass();
// 这里会不会有bug,setter方法会不会有重载的形式,还有会不不会一个bean先有多个property标签
Method method = aClass.getMethod("set" + name, propertyObj.getClass().getInterfaces()[0]);
method.invoke(o, propertyObj);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
// step2:暴露访问对象
// 使用id获取对象
public static Object getBean(String id) {
return beans.get(id);
}
// 使用bean的类型获取对象
public static Object getBean(Class type) {
for (Map.Entry entry : beans.entrySet()) {
String id = entry.getKey();
Object obj = entry.getValue();
Class> aClass = obj.getClass();
// aClass.getTypeName()
if (obj.getClass().getTypeName().equals(type.getTypeName())) {
return obj;
}
}
throw new RuntimeException("未查到指定类型的bean");
}
}
```
### 存在的疑问或者说bug
setter方法会不会重载,这样用setter注入就会有问题
## 事务管理
如何让service中的方法有事务。
1. 首先让执行service层 的方法中的connection对象是同一个,这样就可以进行事务管理
- 解决方案: 把connection对象绑到线程上,ThreadLocal上
2. Dao层的connection链接从ThreadLocal中获取,同时关闭自动提交、
### v2升级
不再把事务代码耦合到service层的方法中
解决方案:使用动态代理
- 新增一个TransactionManger类,用于事务管理
- 新增ProxyFactory类,用于动态代理
依赖关系
- TransactionManager类依赖ConnectionUtil来获取链接
- ProxyFactory类依赖TransactionManager来进行事务控制