自定义ORM(mybatis)源码(一)-解析config.xml
模仿mybatis
配置文件
xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<datasource>
<property key="driverName" value="com.mysql.cj.jdbc.Driver"></property>
<property key="url" value="jdbc:mysql://localhost:3306"></property>
<property key="username" value="test"></property>
<property key="password" value="test"></property>
</datasource>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</config>
解析这个xml ,我们使用 Xpath
Resource
资源读取
java
public class Resource {
/**
* 读取资源文件
* @param path
* @return
*/
public static InputStream getResourceAsStream(String path) {
System.out.println(Resource.class.getClassLoader().getSystemResource("").getPath());
return Resource.class.getClassLoader().getResourceAsStream(path);
}
}
XNodeParser
XPath 解析 document工具
java
public class XNodeParser {
private Document document;
private XPath xPath;
public XNodeParser(Document document) {
this.document = document;
this.xPath = XPathFactory.newInstance().newXPath();
}
/**
*
* <config>
* <mappers>
* <mapper resource="mapper/UserMapper.xml"/>
* </mappers>
* </config>
*
* expression=/config/mappers//mapper 即获取 mappers 下面所有 mapper node 对象节点列表
* @param expression
* @return
* @throws XPathExpressionException
*/
public NodeList getNodeList(String expression) throws XPathExpressionException {
return (NodeList) xPath.compile(expression).evaluate(document, XPathConstants.NODESET);
}
/**
* <config>
* <mappers>
* <mapper resource="mapper/UserMapper.xml"/>
* </mappers>
* </config>
*
* expression=/config/mappers 即获取 mappers node 对象节点
* @param expression
* @return
* @throws XPathExpressionException
*/
public Node getNodeObject(String expression) throws XPathExpressionException {
return (Node) xPath.compile(expression).evaluate(document, XPathConstants.NODE);
}
/**
* <mapper namespace="org.example.sample.dal.UserMapper">
* 获取 namespace 值 即 org.example.sample.dal.UserMapper
* @param node
* @param attributeName
* @return
*/
public static String getAttributeValue(Node node, String attributeName) {
return ((DeferredElementNSImpl) node).getAttribute(attributeName);
}
}
XmlConfigParser
解析 config.xml
java
public abstract class BaseXmlParser {
@Getter
protected Configuration configuration;
public BaseXmlParser(Configuration configuration) {
this.configuration = configuration;
}
protected Document createDocument(InputSource source) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document xml = documentBuilder.parse(source);
xml.getDocumentElement().normalize();
return xml;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public abstract Configuration parse();
}
public class XmlConfigParser extends BaseXmlParser {
private Document document;
public XmlConfigParser(Configuration configuration, InputStream inputStream) {
super(configuration);
this.document = createDocument(new InputSource(inputStream));
}
public Configuration parse() {
parseProperties(this.document, getConfiguration());
return getConfiguration();
}
private Properties parseProperties(Document document, Configuration configuration) {
Properties properties = new Properties();
try {
XNodeParser xNodeParser = new XNodeParser(document);
//解析datasource
extractedDataSource(xNodeParser.getNodeList("/config/datasource//property"), properties, configuration);
//解析xml-mapper
extractedMapper(xNodeParser.getNodeList("/config/mappers//mapper"), properties, configuration);
System.out.println(properties);
return properties;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void extractedMapper(NodeList nodeList, Properties properties, Configuration configuration) {
List<String> mapperLocation = new ArrayList<>();
for (int i = 0; i < nodeList.getLength(); i++) {
Node item = nodeList.item(i);
String resource = XNodeParser.getAttributeValue(item, "resource");
mapperLocation.add(resource);
//解析mapper.xml
XmlMapperParser xmlMapperParser = new XmlMapperParser(Resource.getResourceAsStream(resource), properties, configuration);
xmlMapperParser.parse();
}
properties.put("mapperLocation", mapperLocation);
}
private void extractedDataSource(NodeList nodeList, Properties properties, Configuration configuration) throws Exception {
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(DataSourceProperties.class);
for (int i = 0; i < nodeList.getLength(); i++) {
Node item = nodeList.item(i);
String key = ((DeferredElementNSImpl) item).getAttribute("key");
String value = ((DeferredElementNSImpl) item).getAttribute("value");
beanWrapper.setPropertyValue(key, value);
properties.put(key, value);
}
DataSourceProperties dataSourceProperties = (DataSourceProperties) beanWrapper.getWrappedInstance();
configuration.setDataSourceFactory(new MysqlDataSourceFactory(dataSourceProperties));
}
}
通用的 xml 解析都可以这样处理
Configuration
java
public class Configuration {
@Getter
@Setter
private DataSourceFactory dataSourceFactory;
//Map<stmtId[namespace+sqlId],MappedStatement>
private Map<String, MappedStatement> statements = new ConcurrentHashMap<>();
private MapperRegistry mapperRegistry = new MapperRegistry();
/**
* 注册mapper
* @param mapperClz
*/
public void addMapper(Class<?> mapperClz) {
mapperRegistry.addMapper(mapperClz);
}
/**
* 注册 sql-map
* @param mappedStatement
*/
public void addMappedStatement(MappedStatement mappedStatement) {
statements.put(mappedStatement.getFullId(), mappedStatement);
}
public <T> T getMapper(Class<T> mapper, SqlSession sqlSession) {
return mapperRegistry.getMapper(mapper, sqlSession);
}
/**
* 获取绑定的sql
* mapper.namespace+id
* @param stmtId
* @return
*/
public MappedStatement getMappedStatement(String stmtId){
return statements.get(stmtId);
}
}
good luck!