java中反射詳解及實際應用場景
1、介紹
反射(Reflection)是Java語言的一個特性,它允許程序在運行時動態(tài)地獲取類的信息并操作類或對象的屬性、方法和構造器。
1.1、舉例
想象你有一個密封的盒子(類),正常情況下你只能通過盒子上的按鈕(公共方法)來操作它。而反射就像是一把X光掃描儀,可以讓你不用打開盒子就能看到里面的所有結構(私有字段、方法等),甚至可以繞過正常的操作方式直接控制內部部件。
什么時候需要用到反射呢?
舉個生動例子:
class GameCharacter {
private int health = 100; // 血量
private String name;
public void attack() { /* 攻擊邏輯 */ }
private void cheat() { health = 9999; } // 作弊方法
}沒有反射時:
你只能調用 attack()方法
無法修改血量health
無法調用 cheat()方法
使用反射后:
// 獲取角色類的X光照片
Class<?> clazz = GameCharacter.class;
// 找到血量字段并修改(無視private)
Field healthField = clazz.getDeclaredField("health");
healthField.setAccessible(true); // 萬能鑰匙開鎖
healthField.set(character, 9999); // 修改血量
// 找到作弊方法并調用
Method cheatMethod = clazz.getDeclaredMethod("cheat");
cheatMethod.setAccessible(true);
cheatMethod.invoke(character); // 執(zhí)行作弊這就好比在游戲運行時突然獲得了修改角色屬性的能力!
1.2、作用

2、核心類
Java反射主要涉及以下幾個核心類:
Class:表示類的元數(shù)據(jù)
Field:表示類的字段
Method:表示類的方法
Constructor:表示類的構造器
3、應用場景
3.1、基本反射操作
import java.lang.reflect.*;
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 獲取Class對象的三種方式
Class<?> clazz1 = Class.forName("java.lang.String");
Class<?> clazz2 = String.class;
Class<?> clazz3 = "hello".getClass();
System.out.println("類名: " + clazz1.getName());
System.out.println("簡單類名: " + clazz1.getSimpleName());
// 獲取所有公共方法
System.out.println("\n公共方法:");
Method[] methods = clazz1.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
// 獲取所有聲明的字段(包括私有)
System.out.println("\n所有字段:");
Field[] fields = clazz1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
// 創(chuàng)建實例并調用方法
String str = (String) clazz1.getConstructor(String.class).newInstance("Hello Reflection");
Method lengthMethod = clazz1.getMethod("length");
int length = (int) lengthMethod.invoke(str);
System.out.println("\n字符串長度: " + length);
}
}3.2、動態(tài)加載類
// 根據(jù)配置文件動態(tài)加載類
public class PluginManager {
public void loadPlugin(String className) throws Exception {
Class<?> pluginClass = Class.forName(className);
Object plugin = pluginClass.newInstance();
if (plugin instanceof Runnable) {
((Runnable) plugin).run();
}
}
}
// 使用
PluginManager manager = new PluginManager();
manager.loadPlugin("com.example.MyPlugin"); // 類名可以從配置文件中讀取3.3、調用私有方法(測試時常用)
public class SecretClass {
private String secretMethod(String input) {
return "Secret: " + input;
}
}
// 測試類中使用反射調用私有方法
public class SecretTest {
public static void main(String[] args) throws Exception {
SecretClass instance = new SecretClass();
Class<?> clazz = instance.getClass();
Method secretMethod = clazz.getDeclaredMethod("secretMethod", String.class);
secretMethod.setAccessible(true); // 突破私有限制
String result = (String) secretMethod.invoke(instance, "Hello");
System.out.println(result); // 輸出: Secret: Hello
}
}3.4、JSON/XML序列化與反序列化
3.4.1.json序列化
// 簡單的JSON序列化工具(簡化版)
public class JsonSerializer {
public static String toJson(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
StringBuilder json = new StringBuilder("{");
for (Field field : fields) {
field.setAccessible(true);
json.append("\"").append(field.getName()).append("\":")
.append("\"").append(field.get(obj)).append("\",");
}
json.deleteCharAt(json.length() - 1).append("}");
return json.toString();
}
}
// 使用
class Person {
private String name = "Alice";
private int age = 25;
}
Person person = new Person();
System.out.println(JsonSerializer.toJson(person));
// 輸出: {"name":"Alice","age":25}3.4.2.xml實現(xiàn)
import java.lang.reflect.*;
import java.util.*;
public class XmlSerializer {
public static String toXml(Object obj) throws Exception {
if (obj == null) return "<null/>";
Class<?> clazz = obj.getClass();
StringBuilder xml = new StringBuilder();
// 處理基本類型
if (obj instanceof Number || obj instanceof Boolean || obj instanceof String) {
return "<value>" + obj.toString() + "</value>";
}
// 處理數(shù)組
if (clazz.isArray()) {
xml.append("<array type=\"").append(clazz.getComponentType().getSimpleName()).append("\">");
int length = Array.getLength(obj);
for (int i = 0; i < length; i++) {
xml.append(toXml(Array.get(obj, i)));
}
xml.append("</array>");
return xml.toString();
}
// 處理集合
if (obj instanceof Collection) {
Collection<?> collection = (Collection<?>) obj;
xml.append("<collection>");
for (Object item : collection) {
xml.append(toXml(item));
}
xml.append("</collection>");
return xml.toString();
}
// 處理普通對象
xml.append("<").append(clazz.getSimpleName()).append(">");
for (Field field : clazz.getDeclaredFields()) {
if (Modifier.isTransient(field.getModifiers())) continue;
field.setAccessible(true);
Object value = field.get(obj);
xml.append("<").append(field.getName()).append(">")
.append(toXml(value))
.append("</").append(field.getName()).append(">");
}
xml.append("</").append(clazz.getSimpleName()).append(">");
return xml.toString();
}
public static void main(String[] args) throws Exception {
class Product {
private String id = "P1001";
private String name = "Laptop";
輸出:
<Product><id>P1001</id><name>Laptop</name><price>999.99</price><tags><array type="String"><value>electronics</value><value>computer</value></array></tags></Product>
3.5、反射實現(xiàn)依賴注入
依賴注入是框架(如Spring)中廣泛使用的設計模式,它通過反射機制動態(tài)地將依賴對象注入到目標對象中。
1. 簡單依賴注入實現(xiàn)
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
// 模擬一個簡單的IoC容器
public class SimpleContainer {
private Map<String, Object> beans = new HashMap<>();
// 注冊Bean
public void registerBean(String name, Object bean) {
beans.put(name, bean);
}
// 依賴注入
public void injectDependencies() throws Exception {
for (Object bean : beans.values()) {
// 獲取Bean的所有字段
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
// 檢查是否有@Autowired注解(這里簡化處理)
if (field.getAnnotation(Autowired.class) != null) {
// 獲取字段類型
Class<?> fieldType = field.getType();
// 查找匹配的依賴Bean
Object dependency = findDependency(fieldType);
if (dependency != null) {
// 突破私有訪問限制
field.setAccessible(true);
// 注入依賴
field.set(bean, dependency);
}
}
}
}
}
// 查找匹配的依賴
private Object findDependency(Class<?> type) {
for (Object bean : beans.values()) {
if (type.isAssignableFrom(bean.getClass())) {
return bean;
}
}
return null;
}
}
// 自定義Autowired注解
@interface Autowired {}
// 使用示例
class ServiceA {}
class ServiceB {
@Autowired
private ServiceA serviceA; // 將被自動注入
public void showDependency() {
System.out.println("ServiceB中的ServiceA依賴: " + serviceA);
}
}
public class DITest {
public static void main(String[] args) throws Exception {
SimpleContainer container = new SimpleContainer();
container.registerBean("serviceA", new ServiceA());
container.registerBean("serviceB", new ServiceB());
container.injectDependencies();
ServiceB serviceB = (ServiceB) container.getBean("serviceB");
serviceB.showDependency();
}
}2. 依賴注入原理
Spring框架的依賴注入核心流程:
掃描類路徑,通過反射獲取類的元信息
解析@Component、@Service等注解
解析構造器或字段上的@Autowired注解
通過反射創(chuàng)建Bean實例
通過反射將依賴注入到目標字段或構造器中
3.6、反射實現(xiàn)動態(tài)代理
動態(tài)代理是AOP(面向切面編程)的基礎,它允許在運行時動態(tài)創(chuàng)建代理對象。
1. JDK動態(tài)代理示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 業(yè)務接口
interface UserService {
void addUser(String name);
void deleteUser(String name);
}
// 實際業(yè)務實現(xiàn)
class UserServiceImpl implements UserService {
public void addUser(String name) {
System.out.println("添加用戶: " + name);
}
public void deleteUser(String name) {
System.out.println("刪除用戶: " + name);
}
}
// 代理處理器
class LoggingHandler implements InvocationHandler {
private Object target; // 被代理對象
public LoggingHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增強
System.out.println("準備執(zhí)行: " + method.getName());
// 反射調用原始方法
Object result = method.invoke(target, args);
// 后置增強
System.out.println("執(zhí)行完成: " + method.getName());
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
// 創(chuàng)建代理對象
UserService proxyService = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(realService)
);
// 通過代理調用方法
proxyService.addUser("張三");
proxyService.deleteUser("李四");
}
}
輸出:
準備執(zhí)行: addUser
添加用戶: 張三
執(zhí)行完成: addUser
準備執(zhí)行: deleteUser
刪除用戶: 李四
執(zhí)行完成: deleteUser2. CGLIB動態(tài)代理示例
當目標類沒有實現(xiàn)接口時,可以使用CGLIB庫:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class ProductService {
public void saveProduct(String name) {
System.out.println("保存產(chǎn)品: " + name);
}
}
class ProductMethodInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB代理前置處理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("CGLIB代理后置處理");
return result;
}
}
public class CglibProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ProductService.class);
enhancer.setCallback(new ProductMethodInterceptor());
ProductService proxy = (ProductService) enhancer.create();
proxy.saveProduct("筆記本電腦");
}
}
輸出:
CGLIB代理前置處理
保存產(chǎn)品: 筆記本電腦
CGLIB代理后置處理3.7、反射實現(xiàn)注解處理
Java反射API提供了以下關鍵方法來處理注解:
getAnnotation(Class<T>) - 獲取指定類型的注解
getAnnotations
()- 獲取所有注解isAnnotationPresent(Class<?>) - 檢查是否存在指定注解
1. 定義自定義注解
import java.lang.annotation.*;
// 表注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Table {
String name();
}
// 列注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Column {
String name();
String type();
}2. 使用反射處理注解
代碼示例如下:
import java.lang.reflect.Field;
// 應用注解的實體類
@Table(name = "user_table")
class User {
@Column(name = "user_id", type = "bigint")
private Long id;
@Column(name = "user_name", type = "varchar(50)")
private String name;
@Column(name = "user_age", type = "int")
private Integer age;
// 非持久化字段(無Column注解)
private transient String temp;
}
public class AnnotationProcessor {
public static void main(String[] args) {
// 獲取類注解
Class<User> userClass = User.class;
Table tableAnnotation = userClass.getAnnotation(Table.class);
if (tableAnnotation != null) {
System.out.println("表名: " + tableAnnotation.name());
// 生成建表SQL
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE ").append(tableAnnotation.name()).append("(\n");
// 處理字段注解
Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
Column columnAnnotation = field.getAnnotation(Column.class);
if (columnAnnotation != null) {
sql.append(" ").append(columnAnnotation.name())
.append(" ").append(columnAnnotation.type())
.append(",\n");
}
}
sql.delete(sql.length()-2, sql.length()); // 刪除最后的逗號和換行
sql.append("\n);");
System.out.println("生成的SQL:\n" + sql);
}
}
}
輸出:
表名: user_table
生成的SQL:
CREATE TABLE user_table(
user_id bigint,
user_name varchar(50),
user_age int
);3. 進階注解處理
1. 方法級注解與處理
import java.lang.annotation.*;
import java.lang.reflect.Method;
// 定義權限注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Permission {
String[] roles() default {};
}
// 服務類
class AdminService {
@Permission(roles = {"admin", "superadmin"})
public void deleteUser(String username) {
System.out.println("刪除用戶: " + username);
}
@Permission(roles = {"user", "admin"})
public void viewProfile(String username) {
System.out.println("查看用戶資料: " + username);
}
public void publicMethod() {
System.out.println("公開方法,無需權限");
}
}
public class PermissionProcessor {
public static void main(String[] args) throws Exception {
// 模擬當前用戶角色
String currentRole = "user";
AdminService service = new AdminService();
Method[] methods = service.getClass().getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Permission.class)) {
Permission permission = method.getAnnotation(Permission.class);
boolean hasPermission = false;
// 檢查用戶是否有權限
for (String role : permission.roles()) {
if (role.equals(currentRole)) {
hasPermission = true;
break;
}
}
if (hasPermission) {
System.out.println("允許執(zhí)行: " + method.getName());
method.invoke(service, "testUser");
} else {
System.out.println("拒絕訪問: " + method.getName() +
",需要角色: " + String.join(",", permission.roles()));
}
} else {
// 沒有權限注解的方法可以直接執(zhí)行
System.out.println("執(zhí)行無權限限制方法: " + method.getName());
method.invoke(service);
}
}
}
}
輸出:
允許執(zhí)行: viewProfile
查看用戶資料: testUser
拒絕訪問: deleteUser,需要角色: admin,superadmin
執(zhí)行無權限限制方法: publicMethod
公開方法,無需權限2. 參數(shù)級注解與驗證
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
// 參數(shù)驗證注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface Validate {
int min() default 0;
int max() default Integer.MAX_VALUE;
String pattern() default "";
}
class UserService {
public void createUser(
@Validate(min = 3, max = 20) String username,
@Validate(min = 6, pattern = ".*[0-9].*") String password) {
System.out.println("創(chuàng)建用戶: " + username);
}
}
public class ValidationProcessor {
public static void invokeWithValidation(Object target, Method method, Object... args)
throws Exception {
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Validate validate = parameters[i].getAnnotation(Validate.class);
if (validate != null) {
Object arg = args[i];
if (arg instanceof String) {
String value = (String) arg;
// 檢查長度
if (value.length() < validate.min()) {
throw new IllegalArgumentException(
parameters[i].getName() + " 長度不能小于 " + validate.min());
}
if (value.length() > validate.max()) {
throw new IllegalArgumentException(
parameters[i].getName() + " 長度不能大于 " + validate.max());
}
// 檢查正則表達式
if (!validate.pattern().isEmpty() &&
!value.matches(validate.pattern())) {
throw new IllegalArgumentException(
parameters[i].getName() + " 不符合格式要求");
}
}
}
}
// 所有驗證通過,調用方法
method.invoke(target, args);
}
public static void main(String[] args) throws Exception {
UserService service = new UserService();
Method method = service.getClass().getMethod("createUser", String.class, String.class);
// 測試用例
try {
invokeWithValidation(service, method, "ab", "123456"); // 用戶名太短
} catch (IllegalArgumentException e) {
System.out.println("驗證失敗: " + e.getMessage());
}
try {
invokeWithValidation(service, method, "validUser", "simple"); // 密碼不符合格式
} catch (IllegalArgumentException e) {
System.out.println("驗證失敗: " + e.getMessage());
}
// 成功案例
invokeWithValidation(service, method, "validUser", "pass123");
}
}
輸出結果:
驗證失敗: username 長度不能小于 3
驗證失敗: password 不符合格式要求
創(chuàng)建用戶: validUser3. 模擬Spring MVC的控制器處理
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
// 模擬Spring MVC注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Controller
@interface Controller {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@RequestMapping
@interface RequestMapping {
String path();
String method() default "GET";
}
// 控制器類
@Controller("/user")
class UserController {
@RequestMapping(path = "/list", method = "GET")
public List<String> listUsers() {
return Arrays.asList("Alice", "Bob", "Charlie");
}
@RequestMapping(path = "/add", method = "POST")
public String addUser(String username) {
return "添加用戶成功: " + username;
}
}
public class MvcSimulator {
private Map<String, Method> routeMap = new HashMap<>();
public void init() {
// 掃描所有Controller類
Class<?>[] controllers = {UserController.class}; // 實際框架會掃描包
for (Class<?> controller : controllers) {
Controller controllerAnnotation = controller.getAnnotation(Controller.class);
String basePath = controllerAnnotation.value();
// 處理每個方法
for (Method method : controller.getDeclaredMethods()) {
if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping mapping = method.getAnnotation(RequestMapping.class);
String fullPath = basePath + mapping.path();
routeMap.put(mapping.method() + ":" + fullPath, method);
}
}
}
}
public Object handleRequest(String httpMethod, String path, Object... args)
throws Exception {
String key = httpMethod + ":" + path;
Method method = routeMap.get(key);
if (method != null) {
// 實際框架會處理參數(shù)綁定等復雜邏輯
return method.invoke(method.getDeclaringClass().newInstance(), args);
}
throw new RuntimeException("404 Not Found");
}
public static void main(String[] args) throws Exception {
MvcSimulator simulator = new MvcSimulator();
simulator.init();
// 模擬HTTP請求
Object result1 = simulator.handleRequest("GET", "/user/list");
System.out.println("GET /user/list => " + result1);
Object result2 = simulator.handleRequest("POST", "/user/add", "David");
System.out.println("POST /user/add => " + result2);
try {
simulator.handleRequest("GET", "/not/exist");
} catch (Exception e) {
System.out.println("GET /not/exist => " + e.getMessage());
}
}
}
輸出:
GET /user/list => [Alice, Bob, Charlie]
POST /user/add => 添加用戶成功: David
GET /not/exist => 404 Not Found3.8、代碼提示、idea自動補全
IDE功能:如代碼提示、自動補全等功能利用反射獲取類信息
實現(xiàn)代碼提示和自動補全主要需要以下反射操作:
獲取類的所有公共方法(getMethods())
獲取類的所有聲明方法(getDeclaredMethods())
獲取方法的參數(shù)信息(getParameterTypes())
獲取類的字段信息(getFields(), getDeclaredFields())
獲取類的構造函數(shù)(getConstructors())
1. 類成員自動補全
import java.lang.reflect.*;
import java.util.*;
public class CodeCompletion {
private static final Set<String> JAVA_KEYWORDS = new HashSet<>(Arrays.asList(
"public", "private", "protected", "static", "void", "class", "interface"
));
public static List<String> getClassSuggestions(Class<?> clazz, String prefix) {
List<String> suggestions = new ArrayList<>();
// 獲取公共方法
for (Method method : clazz.getMethods()) {
if (method.getName().startsWith(prefix) {
suggestions.add(method.getName() + "()");
}
}
// 獲取公共字段
for (Field field : clazz.getFields()) {
if (field.getName().startsWith(prefix)) {
suggestions.add(field.getName());
}
}
return suggestions;
}
public static List<String> getContextAwareSuggestions(Class<?> clazz, String context, String prefix) {
List<String> suggestions = new ArrayList<>();
if (context.endsWith(".")) {
// 對象成員提示
try {
Field field = clazz.getField(context.substring(0, context.length()-1));
return getClassSuggestions(field.getType(), prefix);
} catch (Exception e) {
// 處理異常
}
} else if (JAVA_KEYWORDS.contains(context)) {
// 關鍵字后不提示
return suggestions;
} else {
// 類靜態(tài)成員提示
return getClassSuggestions(clazz, prefix);
}
return suggestions;
}
public static void main(String[] args) {
Class<?> stringClass = String.class;
System.out.println("String類以'comp'開頭的方法/字段:");
System.out.println(getClassSuggestions(stringClass, "comp"));
System.out.println("\nString類以'to'開頭的方法/字段:");
System.out.println(getClassSuggestions(stringClass, "to"));
}
}
輸出:
String類以'comp'開頭的方法/字段:
[compareTo(), compareToIgnoreCase()]
String類以'to'開頭的方法/字段:
[toCharArray(), toLowerCase(), toLowerCase(), toUpperCase(), toUpperCase(), toString(), toLowerCase(), toUpperCase()]
2. 方法參數(shù)提示
import java.lang.reflect.*;
import java.util.*;
public class MethodParameterHint {
public static Map<String, List<String>> getMethodParameterHints(Class<?> clazz) {
Map<String, List<String>> hints = new HashMap<>();
for (Method method : clazz.getMethods()) {
List<String> params = new ArrayList<>();
for (Parameter param : method.getParameters()) {
params.add(param.getType().getSimpleName() + " " + param.getName());
}
String methodKey = method.getName() + "(" + String.join(", ", params) + ")";
hints.put(methodKey, params);
}
return hints;
}
public static void printMethodHints(Class<?> clazz, String methodPrefix) {
System.out.println("方法名以'" + methodPrefix + "'開頭的方法簽名:");
for (Method method : clazz.getMethods()) {
if (method.getName().startsWith(methodPrefix)) {
System.out.print(method.getName() + "(");
Parameter[] params = method.getParameters();
for (int i = 0; i < params.length; i++) {
if (i > 0) System.out.print(", ");
System.out.print(params[i].getType().getSimpleName() + " " + params[i].getName());
}
System.out.println(")");
}
}
}
public static void main(String[] args) {
Class<?> listClass = List.class;
System.out.println("List接口所有方法參數(shù)提示:");
Map<String, List<String>> hints = getMethodParameterHints(listClass);
hints.forEach((k, v) -> System.out.println(k));
System.out.println("\n---\n");
printMethodHints(listClass, "add");
}
}
輸出:
List接口所有方法參數(shù)提示:
add(E e)
addAll(Collection<? extends E> c)
...
add(int index, E element)
方法名以'add'開頭的方法簽名:
add(E e)
add(int index, E element)
addAll(Collection<? extends E> c)
addAll(int index, Collection<? extends E> c)4、反射的優(yōu)缺點
優(yōu)點:
極大的靈活性,可以在運行時動態(tài)操作
可以訪問類的私有成員(突破封裝)
適合開發(fā)通用框架和工具
缺點:
性能開銷較大(比直接調用慢)
破壞封裝性,可能帶來安全問題
代碼可讀性降低,調試困難
5、總結
記?。?strong>反射是Java的"元"能力,強大但應慎用,就像超能力不能隨便在公共場合使用一樣!
到此這篇關于java中反射詳解及實際應用場景的文章就介紹到這了,更多相關java反射詳解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java項目中實現(xiàn)使用traceId跟蹤請求全流程日志
這篇文章主要介紹了Java項目中實現(xiàn)使用traceId跟蹤請求全流程日志方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
全鏈路監(jiān)控平臺Pinpoint?SkyWalking?Zipkin選型對比
這篇文章主要為大家介紹了全鏈路監(jiān)控平臺Pinpoint?SkyWalking?Zipkin實現(xiàn)的選型對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-03-03
JavaWeb dbutils執(zhí)行sql命令并遍歷結果集時不能查到內容的原因分析
這篇文章主要介紹了JavaWeb dbutils執(zhí)行sql命令并遍歷結果集時不能查到內容的原因分析及簡單處理方法,文中給大家介紹了javaweb中dbutils的使用,需要的朋友可以參考下2017-12-12

