Classloader kompilasi kustom aplikasi Java EE

Berikut persyaratannya:

  1. Aplikasi web Java EE (di Tomcat)...
  2. Sangat sederhana, hanya JSP, servlet dan toples - tanpa kerangka kerja...
  3. Tidak ada yang perlu dimuat ulang, tidak server, tidak konteksnya, tidak ada...

Idenya, sejauh ini, adalah untuk memperluas WebappClassLoader (catalina.jar) untuk membuat classloader khusus Anda sendiri dan mendaftarkannya di konteks.xml sebagai elemen Loader. Dengan sedikit kode Anda dapat menulis classloader Anda dengan baik, siapa yang akan mengetahui di mana menemukan file sumber java dan kemudian mengkompilasinya menjadi file kelas, jika diperlukan, dan kemudian memuatnya ke dalam memori, ketika diminta untuk melakukannya. Logikanya jelas dan sederhana.

Kecuali:

Bagaimana Jasper mengetahui di mana - secara otomatis - menemukan kelas Anda, yang telah dihasilkan oleh pemuat kelas khusus Anda, sehingga dapat mengkompilasi JSP yang mereferensikannya, dan bahkan menyegarkannya (kelas Anda) dengan cepat? Apakah tidak mungkin untuk mencapainya?

Bagaimana menurutmu?

(Tolong jangan mencoba menyimpangkan pembicaraan dengan menunjuk ke berbagai kerangka kerja yang ada yang menangani hal-hal seperti itu untuk Anda. Persyaratannya sangat spesifik: tidak ada kerangka kerja, tidak ada apa pun)


person Takis Bouyouris    schedule 07.12.2011    source sumber
comment
Dokumentasi Jasper menetapkan bahwa: JDT digunakan untuk mengkompilasi halaman JSP - Kompiler Eclipse JDT Java sekarang digunakan untuk melakukan kompilasi kode sumber JSP java. Kompiler ini memuat dependensi sumber dari classloader kontainer. Ant dan javac masih dapat digunakan.. Jadi pertanyaannya sebenarnya menyangkut container classloader!   -  person Takis Bouyouris    schedule 08.12.2011
comment
Classloader kontainer adalah turunan dari org.apache.catalina.loader.StandardClassLoader. Ini adalah classloader Mesin. Saya tidak melihat cara yang jelas untuk mengganti/melengkapi ini agar berfungsi secara otomatis...   -  person Takis Bouyouris    schedule 08.12.2011


Jawaban (1)


Seseorang dapat menambahkan classloader dalam konteks aplikasi web saat ini (context.xml):

<Context>
    <Loader loaderClass = "gr.nevma.cccl.CompilingClassLoader"/>
</Context>

Dan kemudian buat classloader seperti:

package package gr.nevma.cccl;

import ...

public class CompilingClassLoader extends WebappClassLoader {

    public CompilingClassLoader ( ClassLoader parentClassLoader ) {

        super( parentClassLoader );

    }

    public Class<?> loadClass ( String className, boolean resolve ) throws ClassNotFoundException { 

        Class<?> theClass = null;

        // Do you stuff here
        return theClass;

    }

}

Tapi ini hanya akan membantu jika seseorang ingin dapat memuat kelas secara eksplisit dari classloader itu sendiri dengan memanggil ClassLoader::loadClass(...). Ini tidak akan membantu dalam kompilasi JSP oleh Jasper. Ini berarti ketika Jasper mencoba mengkompilasi JSP yang menggunakan kelas-kelas yang akan dimuat oleh pemuat kelas ini, kompilasi akan gagal, karena Jasper bahkan tidak meminta pemuat kelas ini untuk memuat kelas apa pun sama sekali.

Jadi, dengan cara ini, pemuatan dan pemuatan ulang kelas secara otomatis dapat dilakukan tetapi dengan cara manual. Kelas-kelas ini dapat digunakan secara seragam di seluruh aplikasi web, yaitu halaman JSP!

person Takis Bouyouris    schedule 12.12.2011
comment
Tampaknya metode getResourceAsStream() dari WebappClassLoader dipanggil untuk memuat kelas yang dibutuhkan Jasper untuk mengkompilasi halaman JSP. Dengan kata lain, ketika Jasper mencoba mengkompilasi halaman JSP, ia meminta kelas yang diperlukan dari classloader dengan memanggil getResourceAsStream(). Jadi metode ini perlu ditimpa untuk memuat secara dinamis apa pun yang perlu dimuat... - person Takis Bouyouris; 14.12.2011
comment
Untuk dapat memuat dan memuat ulang kelas apa pun (yaitu mendefinisikannya), seseorang harus menghapus dan membuat lagi pemuat kelasnya. Dengan kata lain, sebuah instance dari classloader hanya dapat memuat (mendefinisikan) sebuah kelas satu kali! Jika kelas perlu dimuat ulang (didefinisikan lagi) maka pemuat kelas baru harus dibuat untuk pekerjaan ini dan pemuat kelas lama harus dihapus. - person Takis Bouyouris; 16.12.2011
comment
Ketika classloader telah memuat sebuah kelas satu kali, tampaknya JVM tidak pernah meminta kelas ini lagi, setidaknya selama memori PermGen (tempat kelas disimpan dalam RAM) tidak penuh. Jadi, hal ini tidak dapat dihindari bahwa classloader dihapus dan dibuat baru agar dapat memuat ulang definisi suatu kelas. Dan ini semakin memperjelas bahwa jika referensi dari kelas yang dimuat ulang tetap ada, maka instance dari pemuat kelas yang memuatnya tidak akan dibuang, bukan sampah yang dikumpulkan. - person Takis Bouyouris; 19.12.2011
comment
Selain itu, dengan melihat kode sumber Tomcat, di kelas JspCompilationContext Jasper, kita dapat melihat bahwa inilah yang dilakukan Jasper untuk mengkompilasi dan memuat ulang halaman JSP! Ia secara berkala memeriksa file sumber JSP untuk mengetahui adanya perubahan dan, jika ada perubahan yang ditemukan, maka ia menghancurkan classloadernya, membuat instance baru, mengkompilasi halaman JSP yang perlu dikompilasi dan memuatnya kembali dengan instance baru dari classloader. Dan ya, ini memang terdengar seperti banyak pekerjaan yang harus dilakukan server, jika kecepatannya diatur dengan sangat sering. - person Takis Bouyouris; 19.12.2011