検索
ホームページJava&#&チュートリアルJava ASM は logback ログレベルの動的切り替え方式を使用します

    背景

    すべてのものには原因と結果があり、すべてはイベント駆動型です。このソリューションのログ レベルの切り替えは、次のような背景から来ています。レベルの切り替えにはサービスを再起動する必要がなく、即時効果が必要です。

    • コードを変更したり、関連する依存関係の構成を追加したりするのはビジネス開発者の責任であり、これには幅広い問題が伴います。

    • 後でジャンク ログを動的にリアルタイム フィルタリングして IO とディスク領域のコストを削減します

    • ログバックの導入

    • 敵と戦争を始める前に、まずは最初だけ 敵の状況を理解することによってのみ、あらゆる戦いで勝利を収めることができます。 logback のログ レベルを動的に切り替える場合は、まず logback について少なくとも予備知識を持ち、既製の実装ソリューションが提供されているかどうかを確認する必要があります。以下は、この要件に関連するログバックの簡単な紹介です。
    • Logback は Java のオープン ソース ログ コンポーネントであり、log4j の創設者によって作成されました。現在 3 つのモジュールに分かれています

    logback-core: コア コード モジュール

    logback-classic: log4j の改良版。

    slf4j
    • logback-access のインターフェースも実装しています。アクセス モジュールとサーブレット コンテナの統合により、Http を通じてログにアクセスする機能が提供されます。
    • ContextInitializer クラスは、ログバック自動構成プロセスの論理実装です。

    • ログ レベルは Logger によって維持され、使用されます。そのメンバー変数 Level は Logger によって維持されます

    • Logger には、異なるパラメーターを持つ 3 つのフィルター ログ出力メソッドがあります: filterAndLog_0_Or3Plus、filterAndLog_1、filterAndLog_2

    • setLevel in Logger はログ レベルを維持するためのものです。

    • #ソリューション
    • 苦労する前に、まず市場計画を理解してください。これは、デザイナーだけでなく製品責任者も、最適なソリューションを模索する方法です。

    • オプション 1: ログバックを自動的にスキャンして更新する

    このソリューションは、ログバックの既製の実装であり、構成がオンになっている限り、いわゆるログ レベルの動的切り替えが可能です。達成される。設定方法: ログバック設定ファイルに、次のようなスケジュールされたスキャナを追加するだけです。 Java ASM は logback ログレベルの動的切り替え方式を使用します

    <configuration scan="true" scanPeriod="30 seconds" debug="false">

    このソリューションは研究開発コストを必要とせず、運用および保守担当者が自分で設定して使用できます。

    欠点は次のとおりです:

    スキャン間隔を調整するたびにサービスを再起動する必要があります

    90 を超えるスキャンの % 本番環境ではログ レベルを頻繁に切り替えることはできず、また切り替えることは許可されていないため、すべて無駄です。

    • 効果はリアルタイムではありません。 1 分ごとまたは数分ごとにスキャンするように設定します。ログ レベルの調整を有効にしても、すぐには有効になりませんが、これは無視できます。

    • このソリューションは、ジャンク ログの破棄に対応できません。特定のキーワード出力に基づいてログを破棄するなどのニーズに対応します。このような歴史的な理由からジャンクログが大量に出力されており、時間コストを考慮すると企業の研究開発の最適化は不可能です。

    • オプション 2: ASM がバイトコードを動的に変更する

      もちろん、インターフェイス API を自分で定義するなど、他の解決策もあります。 Logger の setLevel メソッドを直接呼び出してレベルを調整するには、スプリングブート統合を使用します。
    • これらの計画のいずれも、ビジネス開発の役割の関与を避けることはできません。

      このソリューションは、asm 動的変更命令を通じて、ログ レベルを調整してすぐに有効にするだけではありません。ログのフィルタリングのニーズにも対応できます
    具体的な実装は次のとおりです。ここでは asm の紹介はしません。asm を知らない学生は、asm、java エージェント、jvm の手順をよく理解する必要があります。最初:

    1. アイデアは Maven プロジェクトを作成します

    ## 2. Maven は依存関係を導入します

    <dependencies>
            <dependency>
                <groupId>org.ow2.asm</groupId>
                <artifactId>asm</artifactId>
                <version>7.1</version>
            </dependency>
            <dependency>
                <artifactId>asm-commons</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>7.1</version>
            </dependency>
            <dependency>
                <groupId>com.sun</groupId>
                <artifactId>tools</artifactId>
                <version>1.8</version>
                <scope>system</scope>
                <systemPath>/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/lib/tools.jar</systemPath>
            </dependency>
        </dependencies>
    
    <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-jar-plugin</artifactId>
              <version>3.2.0</version>
              <configuration>
                  <archive>
                      <manifestEntries>
                          <!-- 主程序启动类 -->
                          <Agent-Class>
                              agent.LogbackAgentMain
                          </Agent-Class>
                          <!-- 允许重新定义类 -->
                          <Can-Redefine-Classes>true</Can-Redefine-Classes>
                          <!-- 允许转换并重新加载类 -->
                          <Can-Retransform-Classes>true</Can-Retransform-Classes>
                      </manifestEntries>
                  </archive>
              </configuration>
          </plugin>
          <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <configuration>
                  <source>1.8</source>
                  <target>1.8</target>
                  <encoding>UTF-8</encoding>
                  <compilerArguments>
                      <verbose />
                      <!-- 将jdk的依赖jar打入项目中-->
                      <bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
                  </compilerArguments>
              </configuration>
          </plugin>
      </plugins>
    </build>

    3. attrach 起動クラスを作成します

    package agent;
    import java.lang.instrument.Instrumentation;
    import java.lang.instrument.UnmodifiableClassException;
    /**
     * @author dengbp
     * @ClassName LogbackAgentMain
     * @Description attach 启动器
     * @date 3/25/22 6:27 PM
     */
    public class LogbackAgentMain {
        private static String FILTER_CLASS = "ch.qos.logback.classic.Logger";
        public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
            System.out.println("agentArgs:" + agentArgs);
            inst.addTransformer(new LogBackFileTransformer(agentArgs), true);
            Class[] classes = inst.getAllLoadedClasses();
            for (int i = 0; i < classes.length; i++) {
                if (FILTER_CLASS.equals(classes[i].getName())) {
                    System.out.println("----重新加载Logger开始----");
                    inst.retransformClasses(classes[i]);
                    System.out.println("----重新加载Logger完毕----");
                    break;
                }
            }
        }
    }

    4. Word の実装 セクションコード変換プロセッサ

    package agent;
    import jdk.internal.org.objectweb.asm.ClassReader;
    import jdk.internal.org.objectweb.asm.ClassVisitor;
    import jdk.internal.org.objectweb.asm.ClassWriter;
    import java.lang.instrument.ClassFileTransformer;
    import java.security.ProtectionDomain;
    /**
     * @author dengbp
     * @ClassName LogBackFileTransformer
     * @Description 字节码文件转换器
     * @date 3/25/22 6:25 PM
     */
    public class LogBackFileTransformer implements ClassFileTransformer {
    
        private final String level;
        private static String CLASS_NAME = "ch/qos/logback/classic/Logger";
        public LogBackFileTransformer(String level) {
            this.level = level;
        }
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
            if (!CLASS_NAME.equals(className)) {
                return classfileBuffer;
            }
            ClassReader cr = new ClassReader(classfileBuffer);
            ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
            ClassVisitor cv1 = new LogBackClassVisitor(cw, level);
            /*ClassVisitor cv2 = new LogBackClassVisitor(cv1);*/
            // asm框架使用到访问模式和责任链模式
            // ClassReader 只需要 accept 责任链中的头节点处的 ClassVisitor即可
            cr.accept(cv1, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
            System.out.println("end...");
            return cw.toByteArray();
        }
    }

    5. Logger 要素を実装する訪問者

    package agent;
    import jdk.internal.org.objectweb.asm.ClassVisitor;
    import jdk.internal.org.objectweb.asm.MethodVisitor;
    import org.objectweb.asm.Opcodes;
    /**
     * @author dengbp
     * @ClassName LogBackClassVisitor
     * @Description Logger类元素访问者
     * @date 3/25/22 5:01 PM
     */
    public class LogBackClassVisitor extends ClassVisitor {
        private final String level;
        /**
         * asm版本
         */
        private static final int ASM_VERSION = Opcodes.ASM4;
    
        public LogBackClassVisitor(ClassVisitor classVisitor, String level) {
            super(ASM_VERSION, classVisitor);
            this.level = level;
        }
        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
                                         String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
            return new LogFilterMethodVisitor(api, mv, access, name, descriptor, level);
        }
    }
    Java ASM は logback ログレベルの動的切り替え方式を使用します6. 最終的に Logger のキーメソッドを実装する訪問者

    この訪問者 (クラス)、ログ レベルを切り替えるには、Logger の 3 つのログ フィルタリング メソッドの手順を変更する必要があります。原則として、コマンド ラインに入力されたログ レベル パラメータの値を、そのメンバ変数 activeLevelInt の値で上書きします。長さが長いため、コードのコア部分のみを掲載します。以下を参照してください:

    package agent;
    import jdk.internal.org.objectweb.asm.Label;
    import jdk.internal.org.objectweb.asm.MethodVisitor;
    import jdk.internal.org.objectweb.asm.commons.AdviceAdapter;
    import org.objectweb.asm.Opcodes;
    /**
     * @author dengbp
     * @ClassName LogFilterMethodVisitor
     * @Description Logger类日志过滤方法元素访问者
     * @date 3/25/22 5:01 PM
     */
    public class LogFilterMethodVisitor extends AdviceAdapter {
        private String methodName;
        private final String level;
        private static final String filterAndLog_1 = "filterAndLog_1";
        private static final String filterAndLog_2 = "filterAndLog_2";
        private static final String filterAndLog_0_Or3Plus = "filterAndLog_0_Or3Plus";
        protected LogFilterMethodVisitor(int api, MethodVisitor methodVisitor, int access, String name, String descriptor, String level) {
            super(api, methodVisitor, access, name, descriptor);
            this.methodName = name;
            this.level = level;
        }
        /**
         * Description 在访问方法的头部时被访问
         * @param
         * @return void
         * @Author dengbp
         * @Date 3:36 PM 4/1/22
         **/
        @Override
        public void visitCode() {
            System.out.println("visitCode method");
            super.visitCode();
        }
        @Override
        protected void onMethodEnter() {
            System.out.println("开始重写日志级别为:"+level);
            System.out.println("----准备修改方法----");
            if (filterAndLog_1.equals(methodName)) {
                modifyLogLevel_1();
            }
            if (filterAndLog_2.equals(methodName)) {
                modifyLogLevel_2();
            }
            if (filterAndLog_0_Or3Plus.equals(methodName)) {
                modifyLogLevel_3();
            }
            System.out.println("重写日志级别成功....");
        }

    このうち、modifyLogLevel_1();modifyLogLevel_2();modifyLogLevel_3();は、それぞれ filterAndLog_1、filterAndLog_2、filterAndLog_0_Or3Plus メソッド命令の変更に対応します。

    /**
         * Description 修改目标方法:filterAndLog_1
         * @param
         * @return void
         * @Author dengbp
         * @Date 2:20 PM 3/31/22
         **/
        private void modifyLogLevel_1(){
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(390, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitLdcInsn(level);
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "ch/qos/logback/classic/Level", "toLevel", "(Ljava/lang/String;)Lch/qos/logback/classic/Level;", false);
            mv.visitFieldInsn(Opcodes.GETFIELD, "ch/qos/logback/classic/Level", "levelInt", "I");
            mv.visitFieldInsn(Opcodes.PUTFIELD, "ch/qos/logback/classic/Logger", "effectiveLevelInt", "I");
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(392, l1);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, "ch/qos/logback/classic/Logger", "loggerContext", "Lch/qos/logback/classic/LoggerContext;");
            mv.visitVarInsn(Opcodes.ALOAD, 2);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitVarInsn(Opcodes.ALOAD, 3);
            mv.visitVarInsn(Opcodes.ALOAD, 4);
            mv.visitVarInsn(Opcodes.ALOAD, 5);
            mv.visitVarInsn(Opcodes.ALOAD, 6);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "ch/qos/logback/classic/LoggerContext", "getTurboFilterChainDecision_1", "(Lorg/slf4j/Marker;Lch/qos/logback/classic/Logger;Lch/qos/logback/classic/Level;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Throwable;)Lch/qos/logback/core/spi/FilterReply;", false);
            mv.visitVarInsn(Opcodes.ASTORE, 7);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLineNumber(394, l2);
            mv.visitVarInsn(Opcodes.ALOAD, 7);
            mv.visitFieldInsn(Opcodes.GETSTATIC, "ch/qos/logback/core/spi/FilterReply", "NEUTRAL", "Lch/qos/logback/core/spi/FilterReply;");
            Label l3 = new Label();
            mv.visitJumpInsn(Opcodes.IF_ACMPNE, l3);
            Label l4 = new Label();
            mv.visitLabel(l4);
            mv.visitLineNumber(395, l4);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, "ch/qos/logback/classic/Logger", "effectiveLevelInt", "I");
            mv.visitVarInsn(Opcodes.ALOAD, 3);
            mv.visitFieldInsn(Opcodes.GETFIELD, "ch/qos/logback/classic/Level", "levelInt", "I");
            Label l5 = new Label();
            mv.visitJumpInsn(Opcodes.IF_ICMPLE, l5);
            Label l6 = new Label();
            mv.visitLabel(l6);
            mv.visitLineNumber(396, l6);
            mv.visitInsn(Opcodes.RETURN);
            mv.visitLabel(l3);
            mv.visitLineNumber(398, l3);
            mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"ch/qos/logback/core/spi/FilterReply"}, 0, null);
            mv.visitVarInsn(Opcodes.ALOAD, 7);
            mv.visitFieldInsn(Opcodes.GETSTATIC, "ch/qos/logback/core/spi/FilterReply", "DENY", "Lch/qos/logback/core/spi/FilterReply;");
            mv.visitJumpInsn(Opcodes.IF_ACMPNE, l5);
            Label l7 = new Label();
            mv.visitLabel(l7);
            mv.visitLineNumber(399, l7);
            mv.visitInsn(Opcodes.RETURN);
            mv.visitLabel(l5);
            mv.visitLineNumber(402, l5);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitVarInsn(Opcodes.ALOAD, 1);
            mv.visitVarInsn(Opcodes.ALOAD, 2);
            mv.visitVarInsn(Opcodes.ALOAD, 3);
            mv.visitVarInsn(Opcodes.ALOAD, 4);
            mv.visitInsn(Opcodes.ICONST_1);
            mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
            mv.visitInsn(Opcodes.DUP);
            mv.visitInsn(Opcodes.ICONST_0);
            mv.visitVarInsn(Opcodes.ALOAD, 5);
            mv.visitInsn(Opcodes.AASTORE);
            mv.visitVarInsn(Opcodes.ALOAD, 6);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "ch/qos/logback/classic/Logger", "buildLoggingEventAndAppend", "(Ljava/lang/String;Lorg/slf4j/Marker;Lch/qos/logback/classic/Level;Ljava/lang/String;[Ljava/lang/Object;Ljava/lang/Throwable;)V", false);
            Label l8 = new Label();
            mv.visitLabel(l8);
            mv.visitLineNumber(403, l8);
            mv.visitInsn(Opcodes.RETURN);
            Label l9 = new Label();
            mv.visitLabel(l9);
            mv.visitLocalVariable("this", "Lch/qos/logback/classic/Logger;", null, l0, l9, 0);
            mv.visitLocalVariable("localFQCN", "Ljava/lang/String;", null, l0, l9, 1);
            mv.visitLocalVariable("marker", "Lorg/slf4j/Marker;", null, l0, l9, 2);
            mv.visitLocalVariable("level", "Lch/qos/logback/classic/Level;", null, l0, l9, 3);
            mv.visitLocalVariable("msg", "Ljava/lang/String;", null, l0, l9, 4);
            mv.visitLocalVariable("param", "Ljava/lang/Object;", null, l0, l9, 5);
            mv.visitLocalVariable("t", "Ljava/lang/Throwable;", null, l0, l9, 6);
            mv.visitLocalVariable("decision", "Lch/qos/logback/core/spi/FilterReply;", null, l2, l9, 7);
            mv.visitMaxs(9, 8);
            mv.visitEnd();
        }

    には、modifyLogLevel_1 の実装のみが掲載されています。 7. 最後に、アタッチ エージェントをロードするためのローディング クラスを作成します。

    import com.sun.tools.attach.VirtualMachine;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    
    /**
     * @author dengbp
     * @ClassName MyAttachMain
     * @Description jar 执行命令:
     * @date 3/25/22 4:12 PM
     */
    public class MyAttachMain {
        private static final int ARGS_SIZE = 2;
    
        public static void main(String[] args) {
            if (args == null || args.length != ARGS_SIZE) {
                System.out.println("请输入进程id和日志级别(ALL、TRACE、DEBUG、INFO、WARN、ERROR、OFF),如:31722 info");
                return;
            }
            VirtualMachine vm = null;
            try {
                System.out.println("修改的进程id:" + args[0]);
                vm = VirtualMachine.attach(args[0]);
                System.out.println("调整日志级别为:" + args[1]);
                vm.loadAgent(getJar(), args[1]);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (vm != null) {
                    try {
                        vm.detach();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        private static String getJar() throws UnsupportedEncodingException {
            String jarFilePath = MyAttachMain.class.getProtectionDomain().getCodeSource().getLocation().getFile();
            jarFilePath = java.net.URLDecoder.decode(jarFilePath, "UTF-8");
            int beginIndex = 0;
            int endIndex = jarFilePath.length();
            if (jarFilePath.contains(".jar")) {
                endIndex = jarFilePath.indexOf(".jar") + 4;
            }
            if (jarFilePath.startsWith("file:")) {
                beginIndex = jarFilePath.indexOf("file:") + 5;
            }
            jarFilePath = jarFilePath.substring(beginIndex, endIndex);
            System.out.println("jar path:" + jarFilePath);
            return jarFilePath;
        }
    }

    8. パッケージの実行

    対象のプログラムを検索

      ##jar を実行
    • #
      java  -Xbootclasspath/a:/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/lib/tools.jar  -cp change-log-agent-1.0.1.jar MyAttachMain 52433  DEBUG
      java  -Xbootclasspath/a:/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/lib/tools.jar  -cp change-log-agent-1.0.1.jar MyAttachMain 52433 ERROR
      java  -Xbootclasspath/a:/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/lib/tools.jar  -cp change-log-agent-1.0.1.jar MyAttachMain 52433 INFO
    # ##効果# ##

    Java ASM は logback ログレベルの動的切り替え方式を使用します

    Java ASM は logback ログレベルの動的切り替え方式を使用します

    PS: 検証が失敗した場合 (java.lang.verifyerror が原因)、jvm パラメータを指定してください:-noverify

    以上がJava ASM は logback ログレベルの動的切り替え方式を使用しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明
    この記事は亿速云で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
    Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Apr 25, 2025 am 12:23 AM

    javaispopularforsoss-platformdesktopapplicationsduetoits "writeonce、runaynay" philosophy.1)itusesbytecodatiTatrunnanyjvm-adipplatform.2)ライブラリリケンディンガンドジャヴァフククレアティック - ルルクリス

    Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Apr 25, 2025 am 12:22 AM

    Javaでプラットフォーム固有のコードを作成する理由には、特定のオペレーティングシステム機能へのアクセス、特定のハードウェアとの対話、パフォーマンスの最適化が含まれます。 1)JNAまたはJNIを使​​用して、Windowsレジストリにアクセスします。 2)JNIを介してLinux固有のハードウェアドライバーと対話します。 3)金属を使用して、JNIを介してMacOSのゲームパフォーマンスを最適化します。それにもかかわらず、プラットフォーム固有のコードを書くことは、コードの移植性に影響を与え、複雑さを高め、パフォーマンスのオーバーヘッドとセキュリティのリスクをもたらす可能性があります。

    プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?Apr 25, 2025 am 12:12 AM

    Javaは、クラウドネイティブアプリケーション、マルチプラットフォームの展開、および言語間の相互運用性を通じて、プラットフォームの独立性をさらに強化します。 1)クラウドネイティブアプリケーションは、GraalvmとQuarkusを使用してスタートアップ速度を向上させます。 2)Javaは、埋め込みデバイス、モバイルデバイス、量子コンピューターに拡張されます。 3)Graalvmを通じて、JavaはPythonやJavaScriptなどの言語とシームレスに統合して、言語間の相互運用性を高めます。

    Javaの強力なタイピングは、プラットフォームの独立性にどのように貢献しますか?Javaの強力なタイピングは、プラットフォームの独立性にどのように貢献しますか?Apr 25, 2025 am 12:11 AM

    Javaの強力なタイプ化されたシステムは、タイプの安全性、統一タイプの変換、多型を通じてプラットフォームの独立性を保証します。 1)タイプの安全性は、コンパイル時間でタイプチェックを実行して、ランタイムエラーを回避します。 2)統一された型変換ルールは、すべてのプラットフォームで一貫しています。 3)多型とインターフェイスメカニズムにより、コードはさまざまなプラットフォームで一貫して動作します。

    Javaネイティブインターフェイス(JNI)がプラットフォームの独立性をどのように妥協できるかを説明します。Javaネイティブインターフェイス(JNI)がプラットフォームの独立性をどのように妥協できるかを説明します。Apr 25, 2025 am 12:07 AM

    JNIはJavaのプラットフォームの独立を破壊します。 1)JNIは特定のプラットフォームにローカルライブラリを必要とします。2)ローカルコードをターゲットプラットフォームにコンパイルおよびリンクする必要があります。3)異なるバージョンのオペレーティングシステムまたはJVMは、異なるローカルライブラリバージョンを必要とする場合があります。

    Javaのプラットフォームの独立性を脅かしたり強化したりする新しいテクノロジーはありますか?Javaのプラットフォームの独立性を脅かしたり強化したりする新しいテクノロジーはありますか?Apr 24, 2025 am 12:11 AM

    新しいテクノロジーは、両方の脅威をもたらし、Javaのプラットフォームの独立性を高めます。 1)Dockerなどのクラウドコンピューティングとコンテナ化テクノロジーは、Javaのプラットフォームの独立性を強化しますが、さまざまなクラウド環境に適応するために最適化する必要があります。 2)WebAssemblyは、Graalvmを介してJavaコードをコンパイルし、プラットフォームの独立性を拡張しますが、パフォーマンスのために他の言語と競合する必要があります。

    JVMのさまざまな実装は何ですか、そしてそれらはすべて同じレベルのプラットフォームの独立性を提供しますか?JVMのさまざまな実装は何ですか、そしてそれらはすべて同じレベルのプラットフォームの独立性を提供しますか?Apr 24, 2025 am 12:10 AM

    JVMの実装が異なると、プラットフォームの独立性が得られますが、パフォーマンスはわずかに異なります。 1。OracleHotspotとOpenJDKJVMは、プラットフォームの独立性で同様に機能しますが、OpenJDKは追加の構成が必要になる場合があります。 2。IBMJ9JVMは、特定のオペレーティングシステムで最適化を実行します。 3. Graalvmは複数の言語をサポートし、追加の構成が必要です。 4。AzulzingJVMには、特定のプラットフォーム調整が必要です。

    プラットフォームの独立性は、開発コストと時間をどのように削減しますか?プラットフォームの独立性は、開発コストと時間をどのように削減しますか?Apr 24, 2025 am 12:08 AM

    プラットフォームの独立性により、開発コストが削減され、複数のオペレーティングシステムで同じコードセットを実行することで開発時間を短縮します。具体的には、次のように表示されます。1。開発時間を短縮すると、1セットのコードのみが必要です。 2。メンテナンスコストを削減し、テストプロセスを統合します。 3.展開プロセスを簡素化するための迅速な反復とチームコラボレーション。

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    SecLists

    SecLists

    SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SAP NetWeaver Server Adapter for Eclipse

    SAP NetWeaver Server Adapter for Eclipse

    Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

    SublimeText3 Linux 新バージョン

    SublimeText3 Linux 新バージョン

    SublimeText3 Linux 最新バージョン

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)