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) + + + + +