From b07416ef06405d707e21e1607758bcd8a7ec1fb1 Mon Sep 17 00:00:00 2001
From: aoshiguchen <1052045476@qq.com>
Date: Wed, 3 Aug 2022 23:05:32 +0800
Subject: [PATCH] =?UTF-8?q?SqlMapper=E6=94=AF=E6=8C=81xml=E9=85=8D?=
=?UTF-8?q?=E7=BD=AEsql?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
neutrino-core/pom.xml | 5 ++
.../asgc/neutrino/core/base/GlobalConfig.java | 10 ++++
.../core/bean/AbstractBeanFactory.java | 2 +-
.../asgc/neutrino/core/bean/BeanWrapper.java | 6 +++
.../neutrino/core/bean/SimpleBeanFactory.java | 38 ++++++++++++-
.../neutrino/core/db/mapper/SqlParser.java | 54 +++++++++++++++++--
.../server/base/rest/config/SqliteConfig.java | 1 +
.../proxy/server/dal/UserTokenMapper.java | 8 +--
.../main/resources/mapper/UserTokenMapper.xml | 12 +++++
9 files changed, 127 insertions(+), 9 deletions(-)
create mode 100644 neutrino-proxy-server/src/main/resources/mapper/UserTokenMapper.xml
diff --git a/neutrino-core/pom.xml b/neutrino-core/pom.xml
index 3486d375..f516f75d 100644
--- a/neutrino-core/pom.xml
+++ b/neutrino-core/pom.xml
@@ -48,5 +48,10 @@
velocity-engine-core
2.2
+
+ org.dom4j
+ dom4j
+ 2.1.3
+
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/GlobalConfig.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/GlobalConfig.java
index 63e84c8e..755b3215 100644
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/GlobalConfig.java
+++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/GlobalConfig.java
@@ -21,6 +21,8 @@
*/
package fun.asgc.neutrino.core.base;
+import fun.asgc.neutrino.core.constant.MetaDataConstant;
+
/**
* 全局配置
* @author: aoshiguchen
@@ -46,6 +48,10 @@ public class GlobalConfig {
* 自动生成代码保存路径
*/
private static volatile String generatorCodeSavePath = "./lib/";
+ /**
+ * mapper文件存放基础路径
+ */
+ private static volatile String mapperXmlFileBasePath = MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER.concat("/mapper");
public static boolean isPrintGeneratorCode() {
return isPrintGeneratorCode;
@@ -78,4 +84,8 @@ public class GlobalConfig {
public static void setGeneratorCodeSavePath(String generatorCodeSavePath) {
GlobalConfig.generatorCodeSavePath = generatorCodeSavePath;
}
+
+ public static String getMapperXmlFileBasePath() {
+ return mapperXmlFileBasePath;
+ }
}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java
index 5951aa92..dd38b27b 100644
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java
+++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java
@@ -339,7 +339,7 @@ public abstract class AbstractBeanFactory implements BeanFactory, BeanRegistry,
* @param name
* @return
*/
- private BeanWrapper findBean(Class> type, String name) {
+ protected BeanWrapper findBean(Class> type, String name) {
Assert.notNull(type, "bean的类型不能为空!");
Assert.notNull(name, "bean的名称不能为空!");
return beanCache.get(new BeanIdentity(name, type));
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java
index 032dd9cb..a7db4748 100644
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java
+++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java
@@ -32,6 +32,7 @@ import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.HashSet;
import java.util.Set;
/**
@@ -57,6 +58,7 @@ public class BeanWrapper implements LifeCycle {
private BeanInstantiationMode instantiationMode;
private Method instantiationMethod;
private boolean isNonIntercept;
+ private Set innerDeanIdentitySet = new HashSet<>();
public boolean hasInstance() {
return null != instance;
@@ -150,4 +152,8 @@ public class BeanWrapper implements LifeCycle {
() -> beanIdentity
);
}
+
+ public Set getInnerDeanIdentitySet() {
+ return innerDeanIdentitySet;
+ }
}
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java
index c5cdf753..0c900201 100644
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java
+++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java
@@ -211,12 +211,21 @@ public class SimpleBeanFactory extends AbstractBeanFactory {
} else if (BeanInstantiationMode.METHOD == bean.getInstantiationMode()) {
// 通过bean方法实例化
BeanWrapper factoryBean = bean.getFactoryBean();
+ factoryBean.getInnerDeanIdentitySet().add(bean.getIdentity());
if (!factoryBean.hasInstance()) {
newInstance(factoryBean);
+ }
+ // 工厂bean,实例化方法执行前,工厂bean需要完成注入。但此时如果存在循环引用,这个注入只能完成一部分。实例化完成后,继续注入
+ if (factoryBean.getStatus() == BeanStatus.INSTANCE) {
inject(factoryBean);
}
if (bean.getInstantiationMethod().getParameters().length == 0) {
bean.setInstance(bean.getInstantiationMethod().invoke(factoryBean.getInstance()));
+ // 实例化完成后继续注入
+ if (null != bean.getInstance()) {
+ bean.setStatus(BeanStatus.INSTANCE);
+ }
+ inject(factoryBean);
} else {
// 暂时只处理一个参数的情况
Autowired autowired = bean.getInstantiationMethod().getParameters()[0].getAnnotation(Autowired.class);
@@ -231,6 +240,11 @@ public class SimpleBeanFactory extends AbstractBeanFactory {
arg = getBeanByTypeAndName(beanType, beanName);
}
bean.setInstance(bean.getInstantiationMethod().invoke(factoryBean.getInstance(), arg));
+ // 实例化完成后继续注入
+ if (null != bean.getInstance()) {
+ bean.setStatus(BeanStatus.INSTANCE);
+ }
+ inject(factoryBean);
}
} else if (BeanInstantiationMode.FACTORY == bean.getInstantiationMode()) {
@@ -267,16 +281,35 @@ public class SimpleBeanFactory extends AbstractBeanFactory {
bean.setStatus(BeanStatus.INJECT);
return;
}
+ boolean flag = true;
for (Field field : fieldSet) {
Autowired autowired = field.getAnnotation(Autowired.class);
if (null == autowired) {
continue;
}
+ // 已完成注入,无需重复注入
+ field.setAccessible(true);
+ Object oldObj = field.get(bean.getInstance());
+ if (null != oldObj) {
+ continue;
+ }
+
String beanName = autowired.value();
if (StringUtil.isEmpty(beanName)) {
beanName = field.getName();
}
Class> parameterType = autowired.parameterTypes().length == 0 ? Object.class : autowired.parameterTypes()[0];
+
+ // 临时解决自引用导致堆栈溢出的问题
+ BeanIdentity innerBeanIdentity = new BeanIdentity(beanName, field.getType());
+ if (bean.getInnerDeanIdentitySet().contains(innerBeanIdentity)) {
+ BeanWrapper beanWrapper = findBean(field.getType(), beanName);
+ if (null == beanWrapper || !beanWrapper.hasInstance()) {
+ flag = false;
+ continue;
+ }
+ }
+
BeanMatchMode matchMode = autowired.matchMode();
Object obj = null;
if (matchMode == BeanMatchMode.ByType) {
@@ -302,9 +335,12 @@ public class SimpleBeanFactory extends AbstractBeanFactory {
if (null == obj) {
throw new BeanException(String.format("Bean[type:%s name:%s field:%s] 注入异常", bean.getType().getName(), bean.getName(), field.getName()));
}
+
ReflectUtil.setFieldValue(field, bean.getInstance(), obj);
}
- bean.setStatus(BeanStatus.INJECT);
+ if (flag) {
+ bean.setStatus(BeanStatus.INJECT);
+ }
}
);
} catch (BeanException e){
diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/db/mapper/SqlParser.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/db/mapper/SqlParser.java
index ff4bde84..72f49390 100644
--- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/db/mapper/SqlParser.java
+++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/db/mapper/SqlParser.java
@@ -21,16 +21,26 @@
*/
package fun.asgc.neutrino.core.db.mapper;
+import fun.asgc.neutrino.core.base.GlobalConfig;
import fun.asgc.neutrino.core.cache.Cache;
import fun.asgc.neutrino.core.cache.MemoryCache;
+import fun.asgc.neutrino.core.constant.MetaDataConstant;
import fun.asgc.neutrino.core.db.annotation.*;
+import fun.asgc.neutrino.core.util.CollectionUtil;
+import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.core.util.LockUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.Collection;
+import java.util.Optional;
/**
* sql解析器
@@ -79,6 +89,9 @@ public class SqlParser {
this.targetMethodSign = String.format("%s#%s", targetMethod.getDeclaringClass().getName(), targetMethod.getName());
this.initByAnnotation();
this.initByXml();
+ if (StringUtil.isEmpty(sql)) {
+ throw new RuntimeException(String.format("%s sql不能为空!", targetMethodSign));
+ }
}
/**
@@ -98,7 +111,7 @@ public class SqlParser {
Select select = targetMethod.getAnnotation(Select.class);
this.sql = select.value();
if (StringUtil.isEmpty(sql)) {
- throw new RuntimeException(String.format("%s sql不能为空!", targetMethod));
+ throw new RuntimeException(String.format("%s sql不能为空!", targetMethodSign));
}
this.isReturnCollection = Collection.class.isAssignableFrom(targetMethod.getReturnType());
if (isReturnCollection && null == resultClass) {
@@ -135,10 +148,45 @@ public class SqlParser {
* 根据xml文件进行初始化
*/
private void initByXml() {
- if (!StringUtil.isEmpty(this.sql)) {
+// if (!StringUtil.isEmpty(this.sql)) {
+// return;
+// }
+ String xmlPath = String.format("%s/%s.xml", GlobalConfig.getMapperXmlFileBasePath(), this.targetMethod.getDeclaringClass().getSimpleName());
+ String xmlStr = FileUtil.readContentAsString(xmlPath);
+ if (StringUtil.isEmpty(xmlStr)) {
return;
}
- // TODO
+ try {
+ SAXReader saxReader = new SAXReader();
+ Document document = saxReader.read(new StringReader(xmlStr));
+ Element rootElement = document.getRootElement();
+ if (CollectionUtil.isEmpty(rootElement.elements())) {
+ return;
+ }
+ Optional optionalElement = rootElement.elements().stream().filter(e -> e.attributeValue("id").equals(targetMethod.getName())).findFirst();
+ if (!optionalElement.isPresent()) {
+ return;
+ }
+ Element element = optionalElement.get();
+ this.sql = element.getText().replaceAll("\n", "").replaceAll( " ", " ");
+ if (element.getName().equals("select")) {
+ this.operatorType = SqlOperatorType.SELECT;
+ } else if (element.getName().equals("update")) {
+ this.operatorType = SqlOperatorType.UPDATE;
+ } else if (element.getName().equals("delete")) {
+ this.operatorType = SqlOperatorType.DELETE;
+ } else if (element.getName().equals("insert")) {
+ this.operatorType = SqlOperatorType.INSERT;
+ }
+ if (!StringUtil.isEmpty(element.attributeValue("resultType"))) {
+ this.resultComponentType = Class.forName(element.attributeValue("resultType"));
+ }
+ if (StringUtil.isEmpty(sql)) {
+ throw new RuntimeException(String.format("%s sql不能为空!", targetMethodSign));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(String.format("Mapper文件[%s]异常! %s", xmlPath, e.getMessage()));
+ }
}
public static SqlParser getInstance(Method targetMethod) throws Exception {
diff --git a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/base/rest/config/SqliteConfig.java b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/base/rest/config/SqliteConfig.java
index 20afa6ef..98f6c191 100644
--- a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/base/rest/config/SqliteConfig.java
+++ b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/base/rest/config/SqliteConfig.java
@@ -22,6 +22,7 @@
package fun.asgc.neutrino.proxy.server.base.rest.config;
import fun.asgc.neutrino.core.annotation.Configuration;
+import fun.asgc.neutrino.core.annotation.Init;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.annotation.Value;
import lombok.Data;
diff --git a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/dal/UserTokenMapper.java b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/dal/UserTokenMapper.java
index 4d995e92..8e5f6884 100644
--- a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/dal/UserTokenMapper.java
+++ b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/dal/UserTokenMapper.java
@@ -28,8 +28,6 @@ import fun.asgc.neutrino.core.db.annotation.Select;
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
-import java.util.Date;
-
/**
*
* @author: aoshiguchen
@@ -39,19 +37,21 @@ import java.util.Date;
public interface UserTokenMapper extends SqlMapper {
/**
* 新增用户token
+ * 支持注解 + xml配置2种方式
* @param userToken
* @return
*/
- @Insert("insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`) values (:token,:userId,:expirationTime,:createTime,:updateTime)")
+// @Insert("insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`) values (:token,:userId,:expirationTime,:createTime,:updateTime)")
int add(UserTokenDO userToken);
/**
* 根据token查询单条记录
+ * 支持注解 + xml配置2种方式
* @param token
* @param time
* @return
*/
- @Select("select * from user_token where token = ? and expiration_time > ?")
+// @Select("select * from user_token where token = ? and expiration_time > ?")
UserTokenDO findByAvailableToken(String token, Long time);
/**
diff --git a/neutrino-proxy-server/src/main/resources/mapper/UserTokenMapper.xml b/neutrino-proxy-server/src/main/resources/mapper/UserTokenMapper.xml
new file mode 100644
index 00000000..36e709e0
--- /dev/null
+++ b/neutrino-proxy-server/src/main/resources/mapper/UserTokenMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+ insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`)
+ values (:token, :userId, :expirationTime, :createTime, :updateTime)
+
+
+
+
+