Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2011-2019, hubin ([email protected]).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.codingapi.txlcn.tc.annotation;

import java.lang.annotation.*;

/**
* @author [email protected]
* @since 2019/7/29
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableId {

/**
* 字段值(驼峰命名方式,该值可无)
*/
String value() default "";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2011-2019, hubin ([email protected]).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.codingapi.txlcn.tc.annotation;

import java.lang.annotation.*;

/**
* @author [email protected]
* @since 2019/7/29
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableName {

/**
* 实体对应的表名
*/
String value() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,14 @@ private Map<String, Object> newKeyValues(List<Expression> expressions) {
Map<String, Object> keyValues = new HashMap<>();
for (int i = 0; i < columns.size(); i++) {
columns.get(i).setTable(table);
//解决Long类型字段作为主键空指针异常
if (primaryKeys.contains(columns.get(i).getFullyQualifiedName())) {
Object expression = expressions.get(i).getASTNode().jjtGetValue();
Object expression = null;
if (expressions.get(i).getASTNode() != null) {
expressions.get(i).getASTNode().jjtGetValue();
} else {
expression = expressions.get(i);
}
keyValues.put(columns.get(i).getFullyQualifiedName(),
Reflection.invokeN(expression.getClass(), "getValue", expression, new Object[0]));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.codingapi.txlcn.tc.core.transaction.txc.analy;

import com.codingapi.txlcn.tc.core.transaction.txc.analy.def.PrimaryKeysProvider;
import com.codingapi.txlcn.tc.core.transaction.txc.analy.util.AnnotationUtils;
import com.codingapi.txlcn.tc.core.transaction.txc.analy.util.ClassUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
* @author [email protected]
* @since 2019/7/28
*/
@Component
public class PrimaryKeyListVisitorHandler implements PrimaryKeysProvider {

@Value("${tx-lcn.primary-key-package}")
private String primaryKeyPackage;

@Override
public Map<String, List<String>> provide() {
if (primaryKeyPackage != null) {
//扫描所有注解,把主键拿进来
// 获取特定包下所有的类(包括接口和类)
List<Class<?>> clsList = ClassUtils.getClasses(primaryKeyPackage);
//输出所有使用了特定注解的类的注解值
return AnnotationUtils.getPrimaryKeyList(clsList);
} else {
return null;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.codingapi.txlcn.tc.core.transaction.txc.analy.util;

import com.codingapi.txlcn.tc.annotation.TableId;
import com.codingapi.txlcn.tc.annotation.TableName;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author [email protected]
* @since 2019/7/29
*/
public class AnnotationUtils {

private static Pattern humpPattern = Pattern.compile("[A-Z]");

public static Map<String, List<String>> getPrimaryKeyList(List<Class<?>> clsList) {
if (clsList != null && clsList.size() > 0) {
Map<String, List<String>> map = new HashMap<>(clsList.size());
for (Class<?> cls : clsList) {
//获取类中的所有的方法
boolean classHasAnnotation = cls.isAnnotationPresent(TableName.class);
if (classHasAnnotation) {
TableName tableName = cls.getAnnotation(TableName.class);
if (tableName.value().length() != 0) {
Field[] fields = cls.getDeclaredFields();
String tableIdVale = null;
for (Field field : fields) {
boolean fieldHasAnnotation = field.isAnnotationPresent(TableId.class);
if (fieldHasAnnotation) {
TableId tableId = field.getAnnotation(TableId.class);
//输出注解属性
if (tableId.value().length() != 0) {
tableIdVale = tableId.value();
} else {
//转驼峰
tableIdVale = humpToLine(field.getName());
}
break;
}
}
map.put(tableName.value(), Collections.singletonList(tableIdVale));
}
}
}
return map;
} else {
return null;
}
}

public static String humpToLine(String str) {
Matcher matcher = humpPattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
}
matcher.appendTail(sb);
return sb.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.codingapi.txlcn.tc.core.transaction.txc.analy.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
* @author [email protected]
* @since 2019/7/29
*/
public class ClassUtils {

private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtils.class);

private static final String FILE = "file";
private static final String JAR = "jar";
private static final String CLASS_SIGN = ".class";

/**
* 从包package中获取所有的Class
*
* @param packageName packageName
* @return List
*/
public static List<Class<?>> getClasses(String packageName) {
List<Class<?>> classes = new ArrayList<>();
boolean recursive = true;
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String protocol = url.getProtocol();
if (FILE.equals(protocol)) {
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
} else if (JAR.equals(protocol)) {
JarFile jar;
try {
jar = ((JarURLConnection) url.openConnection()).getJarFile();
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
if (name.charAt(0) == '/') {
name = name.substring(1);
}
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
if (idx != -1) {
packageName = name.substring(0, idx).replace('/', '.');
}
if (idx != -1) {
if (name.endsWith(CLASS_SIGN) && !entry.isDirectory()) {
// 去掉后面的".class" 获取真正的类名
String className = name.substring(packageName.length() + 1, name.length() - 6);
try {
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
LOGGER.error(e.getMessage());
}
}
}
}
}
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
return classes;
}

/**
* 以文件的形式来获取包下的所有Class
*
* @param packageName packageName
* @param packagePath packagePath
* @param recursive recursive
* @param classes classes
*/
private static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes) {
File dir = new File(packagePath);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
File[] dirFiles = dir.listFiles(file -> (recursive && file.isDirectory()) || (file.getName().endsWith(CLASS_SIGN)));
assert dirFiles != null;
for (File file : dirFiles) {
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
} else {
String className = file.getName().substring(0, file.getName().length() - 6);
try {
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
LOGGER.error(e.getMessage());
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.codingapi.txlcn.tracing;

import com.codingapi.txlcn.tracing.spring.TracingSpringContextUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

Expand All @@ -28,4 +30,8 @@
@ComponentScan
public class TracingAutoConfiguration {

@Bean
public TracingSpringContextUtils tracingSpringContextUtils() {
return new TracingSpringContextUtils();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import com.alibaba.fastjson.JSONObject;
import com.codingapi.txlcn.tracing.TracingContext;
import com.codingapi.txlcn.tracing.spring.SpringConfig;
import com.codingapi.txlcn.tracing.spring.TracingSpringContextUtils;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -57,7 +59,19 @@ public Server choose(Object key) {

// 1. 自己加入此事务组调用链
assert Objects.nonNull(registration);
TracingContext.tracing().addApp(registration.getServiceId(), registration.getHost() + ":" + registration.getPort());
//兼容springBoot 2.0以下版本
Boolean exitHost;
try {
exitHost = registration.getHost() != null;
} catch (NoSuchMethodError noSuchMethodError) {
exitHost = false;
}
if (!exitHost) {
SpringConfig springConfig = (SpringConfig) TracingSpringContextUtils.getContext().getBean("springConfig");
TracingContext.tracing().addApp(registration.getServiceId(), springConfig.getHost() + ":" + springConfig.getPort());
} else {
TracingContext.tracing().addApp(registration.getServiceId(), registration.getHost() + ":" + registration.getPort());
}

// 2. 获取所有要访问服务的实例
List<Server> servers = getLoadBalancer().getAllServers();
Expand Down
Loading