最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java類加載器ClassLoader的使用詳解

 更新時(shí)間:2022年12月19日 17:20:25   作者:碼畜c  
類加載器負(fù)責(zé)讀取Java字節(jié)代碼,并轉(zhuǎn)換成java.lang.Class類的一個(gè)實(shí)例的代碼模塊。本文主要和大家聊聊JVM類加載器ClassLoader的使用,需要的可以了解一下

BootstrapClassLoader

加載范圍(根據(jù)系統(tǒng)參數(shù)):

System.getProperty("sun.boot.class.path");

負(fù)責(zé)加載核心類庫(kù),以我的本地的環(huán)境來(lái)展示獲取的內(nèi)容:

D:\development\jdk\jdk8\jre\lib\resources.jar;
D:\development\jdk\jdk8\jre\lib\rt.jar;
D:\development\jdk\jdk8\jre\lib\sunrsasign.jar;
D:\development\jdk\jdk8\jre\lib\jsse.jar;
D:\development\jdk\jdk8\jre\lib\jce.jar;
D:\development\jdk\jdk8\jre\lib\charsets.jar;
D:\development\jdk\jdk8\jre\lib\jfr.jar;
D:\development\jdk\jdk8\jre\classes;
C:\Users\18140\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\222.3345.118\plugins\java\lib\rt\debugger-agent.jar

修改加載范圍:

  • -Xbootclasspath: 重新設(shè)定核心類庫(kù)的搜索路徑,不建議使用。
  • -Xbootclasspath/a: 在已有的-XBootclasspath后面追加搜索路徑。較常用。
  • -Xbootclasspath/p: 在已有的-XBootclasspath前面追加搜索路徑。不常用,因?yàn)榭赡軙?huì)引起依賴丟失。

例(:號(hào)賦參數(shù)值):

java -Xbootclasspath/a:D:\XXXFolder; ProgramName

ExtClassLoader

加載范圍(根據(jù)系統(tǒng)參數(shù)):

System.getProperty("java.ext.dirs");

負(fù)責(zé)加載擴(kuò)展類庫(kù),以我的本地的環(huán)境來(lái)展示獲取的內(nèi)容:

D:\development\jdk\jdk8\jre\lib\ext;
C:\Windows\Sun\Java\lib\ext

修改加載范圍,例(=號(hào)賦參數(shù)值):

java -Djava.ext.dirs=D:\XXXFolder; ProgramName

AppClassLoader

加載范圍(根據(jù)系統(tǒng)參數(shù)):

System.getProperty("java.class.path");

負(fù)責(zé)加載應(yīng)用程序的類與類庫(kù),其實(shí)就是classpath下的內(nèi)容。以我的本地的環(huán)境來(lái)展示獲取的內(nèi)容:

.......
D:\development\jdk\jdk8\jre\lib\rt.jar;
D:\development\idea\workspace\personal\resources-operation\target\classes;
D:\development\maven\apache-maven-resp\org\springframework\boot\spring-boot-starter-web\2.3.7.RELEASE\spring-boot-starter-web-2.3.7.RELEASE.jar;
.......

修改加載范圍,例(空格后賦參數(shù)值):

java -classpath D:\XXXFolder; ProgramName
// 簡(jiǎn)寫
java -cp D:\XXXFolder; ProgramName

類加載器的具體實(shí)現(xiàn)在哪里

Ext、AppClassLoader類加載器在sun.misc.Launcher中,通過內(nèi)部靜態(tài)類的形式進(jìn)行了實(shí)現(xiàn)。

由于BootstrapClassLoader是非java語(yǔ)言實(shí)現(xiàn)的,故沒有對(duì)應(yīng)的內(nèi)部靜態(tài)類,但存有一個(gè)BootClassPathHolder靜態(tài)內(nèi)部類在Launcher中。

public class Launcher {
  static class AppClassLoader extends URLClassLoader {}
  static class ExtClassLoader extends URLClassLoader {}
  private static class BootClassPathHolder {}
}

類加載器的初始化時(shí)機(jī)

public class Launcher {
  public Launcher() {
    ExtClassLoader var1;
    try {
     // 1. 創(chuàng)建ExtClassLoader
     var1 = Launcher.ExtClassLoader.getExtClassLoader();// 68
    } catch (IOException var10) {// 69
     throw new InternalError("Could not create extension class loader", var10);// 70
    }
    try {
     // 2. 創(chuàng)建AppClassLoader,并將ExtClassLoader作為ParentClassLoader
     this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);// 76
    } catch (IOException var9) {// 77
     throw new InternalError("Could not create application class loader", var9);// 78
    }
    // 3. 將AppClassLoader掛載到當(dāng)前線程
    Thread.currentThread().setContextClassLoader(this.loader);// 83
    // ......
  }
}

如何進(jìn)行的類加載

不同的類加載器會(huì)根據(jù)不同的系統(tǒng)參數(shù),獲取不同的一組掃描路徑。并根據(jù)掃描路徑(Path)的類型(文件夾、Jar包),

維護(hù)一組Path與Loader實(shí)例在類加載器的父類URLClassLoader的ucp(URLClassPath)字段中。

當(dāng)我們通過類加載器的loadClass方法加載類時(shí),真正依賴的便是loader。

package sun.misc;
public class URLClassPath {
  private static class Loader implements Closeable {}
  static class JarLoader extends Loader {}
  private static class FileLoader extends Loader {}
}

那么,當(dāng)我們通過lodeClass時(shí),

public static void main(String[] args) throws ClassNotFoundException {
    // 1. 重新設(shè)定ClassPath
    System.setProperty("java.class.path", "D:\\development\\idea\\workspace\\personal\\resources-operation\\target\\classes");
    // 2. 重新初始化Launcher
    Launcher launcher = new Launcher();
    // 3. 獲取AppClassLoader
    ClassLoader classLoader = launcher.getClassLoader();
    // 4. loadClass
    Class<?> aClass = classLoader.loadClass(ResourcesOperationApplication.class.getName());
    System.out.println(aClass.getName());
}

是如何落實(shí)到loader的呢?以AppClassLoader為例:

static class AppClassLoader extends URLClassLoader {
  final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
  // 獲取AppClassLoader實(shí)例
  public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
   // 1. 讀取classpath系統(tǒng)參數(shù)
   final String var1 = System.getProperty("java.class.path");
   // 2. 轉(zhuǎn)為File實(shí)例
   final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
   return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction<AppClassLoader>() {
    public AppClassLoader run() {
     // 3. File轉(zhuǎn)為URL
     URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
     // 3. 創(chuàng)建實(shí)例
     return new AppClassLoader(var1x, var0);
    }
   });
  }
  AppClassLoader(URL[] var1, ClassLoader var2) {
   // 4. 初始化父類,并傳遞了一組URL實(shí)例
   super(var1, var2, Launcher.factory);
   this.ucp.initLookupCache(this);
  }
 // ......
}
public class URLClassLoader extends SecureClassLoader implements Closeable {
  /* The search path for classes and resources */
  private final URLClassPath ucp;
  /* The context to be used when loading classes and resources */
  private final AccessControlContext acc;
  public URLClassLoader(URL[] urls, ClassLoader parent,
          URLStreamHandlerFactory factory) {
   super(parent);
   SecurityManager security = System.getSecurityManager();
   if (security != null) {
    security.checkCreateClassLoader();
   }
   acc = AccessController.getContext();
   // 5. 將URL實(shí)例封裝到URLClassPath中
   ucp = new URLClassPath(urls, factory, acc);
  }
}
public class URLClassPath {
  private ArrayList<URL> path;
  Stack<URL> urls;
  ArrayList<Loader> loaders;
  HashMap<String, Loader> lmap;
  private URLStreamHandler jarHandler;
  private boolean closed;
  public URLClassPath(URL[] var1, URLStreamHandlerFactory var2, AccessControlContext var3) {
    this.path = new ArrayList();// 101
    this.urls = new Stack();// 104
    this.loaders = new ArrayList();// 107
    this.lmap = new HashMap();// 110
    this.closed = false;// 116
    // 6. 將URL封裝到內(nèi)部的path中
    for(int var4 = 0; var4 < var1.length; ++var4) {// 138
     this.path.add(var1[var4]);// 139
    }
    this.push(var1);// 141
    if (var2 != null) {// 142
     this.jarHandler = var2.createURLStreamHandler("jar");// 143
    }
    if (DISABLE_ACC_CHECKING) {// 145
     this.acc = null;// 146
    } else {
     this.acc = var3;// 148
    }
  }
}

但是并沒有發(fā)現(xiàn)關(guān)于將URL轉(zhuǎn)為loader的代碼,那么loader是何時(shí)創(chuàng)建的?以上面的測(cè)試代碼為切入口:

Class<?> aClass = classLoader.loadClass(ResourcesOperationApplication.class.getName());

直接定位到核心方法,前繼的非核心方法就跳過了

public abstract class ClassLoader {
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                // 父系委托機(jī)制
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                }
                if (c == null) {
                    // ...
                    // 查找類資源
                    c = findClass(name);
                    // ...
                }
                // ...
            }
            return c;
        }
    }
    protected Class<?> findClass(final String name) throws ClassNotFoundException {
        final Class<?> result;
        try {
            result = AccessController.doPrivileged(
                new PrivilegedExceptionAction<Class<?>>() {
                    public Class<?> run() throws ClassNotFoundException {
                        // 1. 將類的限定名轉(zhuǎn)為 '/' 分隔的形式,例:life.cqq.xxx.ClassName -> life/cqq/xxx/ClassName.class
                        String path = name.replace('.', '/').concat(".class");
                        // 2. 通過URLClassPath獲取類資源
                        Resource res = ucp.getResource(path, false);
                        if (res != null) {
                            try {
                                // 最終根據(jù)類名 & 已加載的類資源創(chuàng)建Class對(duì)象
                                return defineClass(name, res);
                            } catch (IOException e) {
                                throw new ClassNotFoundException(name, e);
                            } catch (ClassFormatError e2) {
                                if (res.getDataError() != null) {
                                    e2.addSuppressed(res.getDataError());
                                }
                                throw e2;
                            }
                        } else {
                            return null;
                        }
                    }
                }, acc);
        } catch (java.security.PrivilegedActionException pae) {
            throw (ClassNotFoundException) pae.getException();
        }
        if (result == null) {
            throw new ClassNotFoundException(name);
        }
        return result;
    }
}
public class URLClassPath {
    public Resource getResource(String var1, boolean var2) {
        // ......
        Loader var3;
        // 3. getNextLoader:獲取可以處理類資源的loader 
        for (int var5 = 0; (var3 = this.getNextLoader(var4, var5)) != null; ++var5) {// 249
            // 5. 通過獲取到的loader獲取類資源
            Resource var6 = var3.getResource(var1, var2);// 250
            if (var6 != null) {// 251
                return var6;// 252
            }
        }
        return null;// 255
    }
    // getNextLoader最終會(huì)調(diào)用到該方法
    private Loader getLoader(final URL var1) throws IOException {
        try {
            return (Loader) AccessController.doPrivileged(new PrivilegedExceptionAction<Loader>() {// 565
                public Loader run() throws IOException {
                    String var1x = var1.getFile();// 568
                    // 4. 最終的判斷:根據(jù)URL創(chuàng)建不同的loader并返回
                    // url.endsWith("/") && "file".equals(var1.getProtocol() ? FileLoader : JarLoader
                    if (var1x != null && var1x.endsWith("/")) {// 569
                        return (Loader) ("file".equals(var1.getProtocol()) ? new FileLoader(var1) : new Loader(var1));// 570
                    } else {
                        return new JarLoader(var1, URLClassPath.this.jarHandler, URLClassPath.this.lmap,
                            URLClassPath.this.acc);// 576
                    }
                }
            }, this.acc);
        } catch (PrivilegedActionException var3) {// 580
            throw (IOException) var3.getException();// 581
        }
    }
}

可以發(fā)現(xiàn),loader其實(shí)是懶加載的。僅有當(dāng)已有l(wèi)oader無(wú)法加載時(shí),會(huì)從path列表中讀取仍未被創(chuàng)建loader的path并創(chuàng)建loader。

總結(jié)一下:

類加載器會(huì)根據(jù)系統(tǒng)參數(shù)創(chuàng)建對(duì)應(yīng)的適配類型的Loader(FileLoader | JarLoader),且Loader是懶加載的。并維護(hù)在父類URLClassLoader的ucp(URLClassPath)屬性中的loaders列表中。

loadClass時(shí),最終會(huì)執(zhí)行g(shù)etResource方法,迭代Loader實(shí)例集合,嘗試獲取資源實(shí)例。最終根據(jù)類名 & 已加載的類資源在defineClass中創(chuàng)建Class對(duì)象。

Loader.getResource(resourceName)

這個(gè)方法有必要說明一下,為后繼獲取資源文件問題做下鋪墊。方法是用法就是獲取資源,在loadClass方法時(shí)獲取類文件,類文件抽象來(lái)說也是一種資源,只是loadClass方法中多了一些關(guān)于類的處理。

當(dāng)我們獲取的非類文件資源,而是其他資源,如不同類型的配置文件,那么這些資源在哪里,如何加載,是需要說清的兩個(gè)問題。

  • where問題的答案其實(shí)就是當(dāng)前類加載器能夠搜索的范圍是什么,即設(shè)定的系統(tǒng)參數(shù)。
  • 如何加載說的也是前面提到的loader,不同的loader(file、jar)處理不同的內(nèi)容。比如FileLoader就會(huì)判斷資源是否在目錄下,那么JarLoader便是判斷資源是否在Jar包中。
public class URLClassPath {
    public Resource getResource(String var1, boolean var2) {
        // ......
        Loader var3;
        for (int var5 = 0; (var3 = this.getNextLoader(var4, var5)) != null; ++var5) {// 249
            // 0. 通過獲取到的loader獲取類資源
            Resource var6 = var3.getResource(var1, var2);// 250
            if (var6 != null) {// 251
                return var6;// 252
            }
        }
        return null;// 255
    }
    // 1. 文件加載器
    private static class FileLoader extends Loader {
        private File dir;
        // ...
        Resource getResource(final String var1, boolean var2) {
            try {
                URL var4 = new URL(this.getBaseURL(), ".");// 1370
                final URL var3 = new URL(this.getBaseURL(), ParseUtil.encodePath(var1, false));// 1371=
                if (!var3.getFile().startsWith(var4.getFile())) {// 1373
                    return null;// 1375
                } else {
                    if (var2) {// 1378
                        URLClassPath.check(var3);// 1379
                    }
                    // 1) 根據(jù)loader對(duì)應(yīng)的文件目錄,拼接資源路徑參數(shù)構(gòu)建File實(shí)例
                    final File var5;
                    if (var1.indexOf("..") != -1) {// 1382
                        var5 = (new File(this.dir, var1.replace('/', File.separatorChar))).getCanonicalFile();// 1383 1384
                        if (!var5.getPath().startsWith(this.dir.getPath())) {// 1385
                            return null;// 1387
                        }
                    } else {
                        var5 = new File(this.dir, var1.replace('/', File.separatorChar));// 1390
                    }
                    // 2) 若File實(shí)例映射的文件存在,則返回Resource實(shí)例,否則返回空
                    return var5.exists() ? new Resource() {// 1393
                        // ...
                    } : null;// 1407
                }
            } catch (Exception var6) {// 1404
                return null;// 1405
            }
        }
    }
    // 2. Jar加載器
    static class JarLoader extends Loader {
        Resource getResource(String var1, boolean var2) {
            if (this.metaIndex != null && !this.metaIndex.mayContain(var1)) {// 1059 1060
                return null;// 1061
            } else {
                try {
                    this.ensureOpen();// 1066
                } catch (IOException var5) {// 1067
                    throw new InternalError(var5);// 1068
                }
                // 1) 若loader對(duì)應(yīng)Jar包中,存有資源名稱的節(jié)點(diǎn),則返回資源節(jié)點(diǎn)內(nèi)容
                JarEntry var3 = this.jar.getJarEntry(var1);// 1070
                if (var3 != null) {// 1071
                    return this.checkResource(var1, var2, var3);// 1072
                } else if (this.index == null) {// 1074
                    return null;// 1075
                } else {
                    HashSet var4 = new HashSet();// 1077
                    return this.getResource(var1, var2, var4);// 1078
                }
            }
        }
    }
}

對(duì)于應(yīng)用層的開發(fā)者而言,需要通過ClassLoader.gerResource(resourceName)進(jìn)行調(diào)用。

public abstract class ClassLoader {
    // 1. 獲取資源也會(huì)遵循父系委托機(jī)制
    public URL getResource(String name) {
        URL url;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
            url = getBootstrapResource(name);
        }
        if (url == null) {
            url = findResource(name);
        }
        return url;
    }
    protected URL findResource(String name) {
        return null;
    }
}
public class URLClassLoader extends SecureClassLoader implements Closeable {
    public URL findResource(final String name) {
        /*
         * The same restriction to finding classes applies to resources
         */
        URL url = AccessController.doPrivileged(
            new PrivilegedAction<URL>() {
                public URL run() {
                    // 2. 繼續(xù)通過類加載器在父類中維護(hù)的URLClassPath獲取資源
                    return ucp.findResource(name, true);
                }
            }, acc);
        return url != null ? ucp.checkURL(url) : null;
    }
}
public class URLClassPath {
    public URL findResource(String var1, boolean var2) {
        int[] var4 = this.getLookupCache(var1);// 224
        // 3. 本質(zhì)還是迭代loader集合進(jìn)行資源獲取
        Loader var3;
        for(int var5 = 0; (var3 = this.getNextLoader(var4, var5)) != null; ++var5) {// 225
            URL var6 = var3.findResource(var1, var2);// 226
            if (var6 != null) {// 227
                return var6;// 228
            }
        }
        return null;// 231
    }
}

調(diào)用獲取資源方法的一些常見問題

Class.getResource & ClassLoader.getResource 的差異

通過ClassLoader獲取資源已經(jīng)在上面說過了,主要在于通過Class對(duì)象調(diào)用getResource方法有什么特別之處?

public final class Class<T> implements java.io.Serializable,
    GenericDeclaration,
    Type,
    AnnotatedElement {
    // 本質(zhì)依舊是調(diào)用ClassLoader.getResource,唯一的不同在于對(duì)于資源名稱進(jìn)行了一次特殊處理。
    // 做了哪些處理正如官方注釋所描述:
    // 1. 如果是絕對(duì)路徑(以 '/' 開頭),剔除 '/' 符號(hào)后返回
    // 2. 如果非絕對(duì)路徑,則拼接'.'號(hào)轉(zhuǎn)為'/'后的包名作為前綴后返回
    // 其實(shí)理解下來(lái)就是:以當(dāng)前類文件所在的包為基準(zhǔn),進(jìn)行相對(duì)、絕對(duì)路徑的拼接。絕對(duì)路徑則不采用包名作為前綴,相對(duì)路徑則以類所在的包名作為前綴。
    public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl == null) {
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }
    /**
     * Add a package name prefix if the name is not absolute Remove leading "/"
     * if name is absolute
     */
    private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }
}

加載不同文件目錄 或 Jar包中含有的同名資源

比如classpath中包含的不同目錄、Jar包下都有一個(gè)同名文件config.properties,那么到底該加載哪一個(gè)呢?

根據(jù)之前的源碼分析,可以推斷出目錄或jar對(duì)應(yīng)的loader,哪個(gè)最先執(zhí)行,則返回該loader對(duì)應(yīng)的目錄或者jar下的config.properties。

如果我想要獲取所有的同名文件呢?

Enumeration<URL> resources = classLoader.getResources("config.properties");
while (resources.hasMoreElements()) {
    URL url = resources.nextElement();
    // do something
}

到此這篇關(guān)于Java類加載器ClassLoader的使用詳解的文章就介紹到這了,更多相關(guān)Java ClassLoader內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Jtable和JTree的寫法示例代碼

    Jtable和JTree的寫法示例代碼

    這篇文章主要介紹了Jtable和JTree的基本概念,常用構(gòu)造方法,以及二者的通用寫法,需要的朋友可以了解下。
    2017-09-09
  • java中邏輯控制舉例具體講解

    java中邏輯控制舉例具體講解

    Java程序邏輯控制通俗說就是對(duì)代碼執(zhí)行順序的控制,這篇文章主要給大家介紹了關(guān)于java中邏輯控制的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Kafka?在?java?中的基本使用步驟

    Kafka?在?java?中的基本使用步驟

    本文給大家介紹Kafka在java中的基本使用,本文分步驟結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-09-09
  • 詳解Java中NullPointerException異常的原因詳解以及解決方法

    詳解Java中NullPointerException異常的原因詳解以及解決方法

    這篇文章主要介紹了詳解Java中NullPointerException異常的原因詳解以及解決方法。文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • SpringBoot讀取配置文件的四種方式

    SpringBoot讀取配置文件的四種方式

    在 Spring Boot 中,application.yml 文件用于配置應(yīng)用程序的屬性,Spring Boot 默認(rèn)會(huì)從 src/main/resources 目錄下的 application.properties 或 application.yml 文件中讀取配置,本文介紹了SpringBoot讀取配置文件的四種方式,需要的朋友可以參考下
    2024-08-08
  • java對(duì)于目錄下文件的單詞查找操作代碼實(shí)現(xiàn)

    java對(duì)于目錄下文件的單詞查找操作代碼實(shí)現(xiàn)

    這篇文章主要介紹了java對(duì)于目錄下文件的單詞查找操作代碼實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java實(shí)現(xiàn)的文件過濾代碼分享(按后輟過濾)

    Java實(shí)現(xiàn)的文件過濾代碼分享(按后輟過濾)

    這篇文章主要介紹了Java實(shí)現(xiàn)的文件過濾代碼分享,本文通過后輟名過濾,代碼寫簡(jiǎn)潔,容易看懂,需要的朋友可以參考下
    2014-07-07
  • Java MyBatis-Plus之初始MyBatis

    Java MyBatis-Plus之初始MyBatis

    MyBatis-Plus是一個(gè)MyBatis的增強(qiáng)工具,在MyBatis的基礎(chǔ)上只做增強(qiáng)不做修改,為簡(jiǎn)化開發(fā)、提高效率而生,本文給大家介紹MyBatis-Plus簡(jiǎn)介和快速入門教程,需要的朋友參考下吧
    2021-10-10
  • Springboot配置管理Externalized?Configuration深入探究

    Springboot配置管理Externalized?Configuration深入探究

    這篇文章主要介紹了Springboot配置管Externalized?Configuration深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Mybatis @SelectKey用法解讀

    Mybatis @SelectKey用法解讀

    這篇文章主要介紹了Mybatis @SelectKey用法解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評(píng)論

若尔盖县| 土默特右旗| 绥芬河市| 内丘县| 天水市| 东源县| 图木舒克市| 彝良县| 乌拉特后旗| 舟曲县| 出国| 普格县| 当阳市| 赤水市| 虞城县| 兴仁县| 远安县| 通辽市| 曲麻莱县| 昭觉县| 永嘉县| 皋兰县| 汉寿县| 禹城市| 修武县| 朝阳县| 凌云县| 固镇县| 遂宁市| 安义县| 巩留县| 桂东县| 宣汉县| 江口县| 宕昌县| 涟水县| 瑞安市| 杭州市| 翁牛特旗| 丹阳市| 石家庄市|