إذا كنت تستخدم Logback كمكون تسجيل الدخول في التطبيق الخاص بك ، فسيقوم معظمهم بتكوين ملف `logback.xml`. بالإضافة إلى ذلك ، في بيئة الإنتاج ، يمكنك تعديل مستوى السجل مباشرة في ملف logback.xml ، ويمكن أن يصدر ساري المفعول دون إعادة تشغيل التطبيق. لذا ، كيف يتم تنفيذ هذه الوظيفة؟
إذا كنت تستخدم Logback كمكون تسجيل الدخول في التطبيق الخاص بك ، فسيقوم معظمهم بتكوين ملف Logback.xml. بالإضافة إلى ذلك ، في بيئة الإنتاج ، يمكنك تعديل مستوى السجل مباشرة في ملف logback.xml ، ويمكن أن يصدر ساري المفعول دون إعادة تشغيل التطبيق.
لذا ، كيف يتم تنفيذ هذه الوظيفة؟
1. وصف المشكلة والتحليل
استجابة للمشكلة أعلاه ، رمي أولاً حالة فعلية. في موقع الويب الشخصي الخاص بي Z+، تتم إضافة جميع الأدوات ديناميكيًا وإخفاءها من خلال ملفات التكوين. نظرًا لوجود خادم واحد فقط ، يتم تبسيط ملفات التكوين ووضعها مباشرة في دليل على الخادم.
الآن عندما أواجه مشكلة ، أحتاج إلى إدراك التغيير عندما يتغير محتوى هذا الملف ، يمكن للتطبيق الشعور بالتغيير ، وإعادة تحميل محتوى الملف ، وتحديث ذاكرة التخزين المؤقت الداخلية للتطبيق
واحدة من أسهل الطرق للتفكير هي الاقتراع لتحديد ما إذا كان قد تم تعديل الملف. إذا تم تعديله ، فسيتم إعادة تحميله وتحديثه. لذلك ، فإن القضايا الرئيسية التي تحتاج إلى القلق بشأنها هي على النحو التالي:
الثاني. التصميم والتنفيذ
بعد استخلاص المشكلة ، يكون الحل المقابل أكثر وضوحًا
ثم يكون التنفيذ البسيط للغاية أسهل:
فئة عامة fileuptest {private long last time ؛ test public void testfileupdate () {file file = file new ("/tmp/erarlyconfig") ؛ // أولاً ، آخر طابع زمني تم تعديله للملف Last Time = file.lastmodified () ؛ // مهمة Timed ، تحدد ما إذا كان الملف قد تغير كل ثانية ، أي ، يحدد ما إذا كان التغييرات المعدلة في SchededExecutorService ScheduledExecutorService = Executors.NewScheduledThreadPool (1) ؛ ScrimeDexecutorService.ScheDuleAtfixedRate (new RunNable () {Override public void run () {if (file.lastmodified ()> last time) {system.out.println ("تحديث الملف! الوقت:" file.lastmodified ()) Timunit.Seconds) ؛ حاول {thread.sleep (1000 * 60) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ }}}ما سبق هو تطبيق بسيط للغاية وأساسي للغاية ، والذي يمكن أن يلبي احتياجاتنا بشكل أساسي. إذن ما هي مشكلة هذا التنفيذ؟
ماذا يحدث إذا حدث استثناء أثناء تنفيذ مهمة التوقيت؟
إجراء بعض التعديلات على الكود أعلاه
فئة عامة fileuptest {private long last time ؛ private void tt () {رمي nullpointerexception () جديد ؛ } test public void testfileupdate () {file file = file new ("/tmp/areraLconfig") ؛ last time = file.lastmodified () ؛ ScripedExecutorService ScheduledExecutorService = Executors.NewScheduledThreadPool (1) ؛ ScrimeDexecutorService.ScheDuleAtfixedRate (new RunNable () {Override public void run () {if (file.lastmodified ()> last time) {system.out.println ("تحديث الملف! Timunit.Seconds) ؛ حاول {thread.sleep (1000 * 60 * 10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ }}}في الاختبار الفعلي ، وجدت أن الكود أعلاه قد تم تشغيله فقط عند تعديل التعديل الأول ، لكن التعديل مرة أخرى سيكون عديم الفائدة. هذا هو ، عندما تم طرح استثناء ، لن يتم تنفيذ مهمة التوقيت. السبب الرئيسي لهذه المشكلة هو أن SignedExecutorService
تحقق من تعليمات تعليق رمز المصدر من ScripedExecutorService مباشرة
إذا واجه أي تنفيذ للمهمة استثناء ، يتم قمع عمليات الإعدام اللاحقة. وإلا ، ستنتهي المهمة فقط من خلال إلغاء أو إنهاء المنفذ.
لذلك ، عند استخدام هذا الموقف ، يجب عليك التأكد من أن مهمتك لا ترمي استثناءات ، وإلا فلن تتمكن من اللعب لاحقًا
الحل المقابل بسيط نسبيًا ، فقط أمسك به
ثالثا. طبعة متقدمة
السابق هو نسخة تنفيذ أساسية. بالطبع ، في دائرة Java ، هناك في الأساس العديد من الاحتياجات الشائعة التي يمكن العثور عليها لاستخدام أدوات المصدر المفتوح المقابلة. بالطبع ، هذا ليس استثناءً ، ويجب أن تكون سلسلة Apache أن كل شخص لديه المزيد من السمات.
بادئ ذي بدء ، تبعيات Maven
<Rependency> <roupiD> commons-io </rougeid> <StifactId> commons-io </shintifactid> <الإصدار> 2.6 </version> </sependency>
بشكل رئيسي ، نستخدم filealterationobserver و filealterationlistener و filealterationmonitor في هذه الأداة لتنفيذ سيناريوهات المتطلبات ذات الصلة. بالطبع ، من السهل جدًا الاستخدام ، لذلك لا أعرف كيفية شرح ذلك. انظر فقط إلى الكود المنصوص عليه من أحد مشاريع المصدر المفتوح Quick-Alarm.
Public Class PropertiesConflistenerHelper {public static boolean registerConfChangelistener (ملف الملف ، الوظيفة <file ، map <string ، eravConfig >> func) {try {// incling stereal 5 sextals veral = timeUnit.seconds.tomillis (5) ؛ // لأنه يتم تنفيذ الاستماع في الدلائل ، يتم الحصول على دليل الجذر للملف مباشرة هنا ملف dir = file.getParentFile () ؛ // إنشاء مراقب ملف لتصفية FileAlterationObserver Observer = new FileAleTationObserver (dir ، filefilterutils.and (filefilterutils.filefilefilter () ، filefilterutils.namefilefilter (file.getName ()))) ؛ // SET FILE DANEST DELANDER SEBSERVER.AddListener (New MyFilelistener (FUNC)) ؛ مراقب FileAlterationMonitor = FileAlterationMonitor الجديد (الفاصل ، المراقب) ؛ monitor.start () ؛ العودة صحيح. } catch (استثناء e) {log.error ("سجل خصائص تغيير خطأ المستمع! e: {}" ، e) ؛ العودة كاذبة }} الفئة النهائية الثابتة myfilelistener يمتد fileAlterationListenerAdaptor {private function <file ، map <string ، erastConfig >> func ؛ public myfilelistener (وظيفة <file ، خريطة <string ، eravConfig >> func) {this.func = func ؛ } Override public void onFileChange (ملف ملف) {map <string ، erastConfig> ans = func.apply (file) ؛ // إذا فشل التحميل ، فقم بطباعة سجل. }}}للتنفيذ أعلاه ، بعض التفسيرات الموجزة:
سؤال ، ماذا يحدث إذا تم طرح استثناء عند تنفيذ طريقة FUNC؟
نتائج الاختبار الفعلية هي نفسها أعلاه. بعد إلقاء استثناء ، لا يزال يتعين عليك توخي الحذر وعدم تشغيل الاستثناء.
لذلك ، دعونا نلقي نظرة على منطق التنفيذ أعلاه ونتقدر مباشرة الوحدة الأساسية.
public void run () {بينما (true) {if (this.running) {iterator var1 = this.observers.iterator () ؛ بينما (var1.hasnext ()) {fileAlterationObserver Observer = (FileAlterationObserver) var1.next () ؛ Observer.CheckandNotify () ؛ } if (this.running) {try {thread.sleep (this.interval) ؛ } catch (interruptedException var3) {؛ } يكمل؛ } } يعود؛ }}يتضح بشكل أساسي مما سبق أن منطق التنفيذ بأكمله يختلف عن طريقة مهمة التوقيت الأولى لدينا. هنا نستخدم المواضيع والحلقات الميتة مباشرة ، وتستخدم طرق النوم للتوقف داخليًا. لذلك ، عندما يحدث استثناء ، فإنه يعادل رميه مباشرة ، وسوف يركع الخيط.
إصدار JDK التكميلي
يوفر JDK1.7 خدمة WatchService ، والتي يمكن استخدامها أيضًا لمراقبة تغييرات الملفات. لم أتعرض لها من قبل ، لذلك اكتشفت أن هناك هذا الشيء. ثم بحثت عن استخدام المعلومات ذات الصلة ووجدت أنه بسيط للغاية. لقد رأيت منشورًا مدونة يشرح أنه يحركه الحدث وله كفاءة أعلى. هنا مثال بسيط
testpublic void testfileupwather () يلقي IoException {// تعليمات ، يجب أن يكون المستمع هنا أيضًا مسار الدليل = paths.get ("/tmp") ؛ WatchService Watcher = filesystems.getDefault (). NewWatchService () ؛ path.register (Watcher ، enter_modify) ؛ New Thread (() -> {try {while (true) {watchkey key = watcher.take () ؛ for (watchevent <؟> الحدث: key.pollevents ()) {if (event.kind () == overflow) {// قد يتم فقدان الحدث أو التخلص منه. } if (! key.reset () {// reset watchkey break ؛ حاول {thread.sleep (1000 * 60 * 10) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ }}رابعا. ملخص
يتضمن استخدام Java لتنفيذ مراقبة تغيير ملفات التكوين بشكل أساسي نقطتين
وعموما ، هذا التنفيذ بسيط نسبيا. سواء كان تطبيقًا مخصصًا أو يعتمد على Commos-IO ، فليس له الكثير من التكلفة الفنية ، ولكن هناك شيء واحد يجب ملاحظته هو:
من أجل تجنب الموقف أعلاه ، فإن التنفيذ الذي يمكن القيام به هو استخدام إشعار الرسائل غير المتزامن لـ EventBus. بعد تغيير الملف ، أرسل رسالة ، ثم أضف شرحًا توضيحيًا لـ SubScribe إلى الطريقة المحددة لإعادة تحميل محتويات الملف. هذا لا يدرك فقط فك الارتباط ، ولكنه يتجنب أيضًا استثناءات الخدمة الناتجة عن الاستثناءات (إذا كنت مهتمًا بهذا التنفيذ ، فيمكنك التعليق والشرح)
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.