1

実行時にクラスファイルを作成しています。

クラスローダーで既存のクラスファイルを更新したものに置き換えたいです。

これは、サーバーの再起動と再デプロイを回避するホット スワップ (JRebel など) に似ています。

コンテキストをリロードするための tomcat の context.xml アプローチを見つけました。ただし、本番環境の場合はあまり役に立ちません。

実行時に ClassLoader にクラスを登録できますか? 実行時にクラスをリロードする代替手段があるかどうかを提案してください。


次のコードを使用して、現在の classLoader を取得しています。

ClassLoader classLoader = LoggingAspect.class.getClassLoader();

以下はロードクラスメソッドの実装です。

public class AspectClassLoader extends ClassLoader{

@Override
public synchronized Class<?> loadClass(String name) throws ClassNotFoundException
{
    String customLoadClass = "com.log.LoggingAspect";
    try
    {
        if(!customLoadClass.equals(name))
        {
            return super.loadClass(name);
        }
        else
        {
            URL classLoadUrl = new URL(this.reloadClassUrl);
            URLConnection connection = classLoadUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();

            while(data != -1){
                buffer.write(data);
                data = input.read();
            }

            input.close();

            byte[] classData = buffer.toByteArray();
            return defineClass(name, classData, 0, classData.length);
        }
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    return null; 
}

クラスをリロードするには、次のコードを使用しています。

AspectClassLoader urlClsLoader = new AspectClassLoader(classLoader);
Class aspect = urlClsLoader.reloadClass("com.log.LoggingAspect", true, new String("file:"+className));

クラスローダーの私の reload メソッドは

public synchronized Class<?> reloadClass(String name, boolean resolve, String reloadClassUrl) throws ClassNotFoundException
{
    this.reloadClassUrl = reloadClassUrl;
    return this.loadClass(name, resolve);
}

LoggingAspect の新しいインスタンスを作成するとリロードした後も、古いインスタンスが表示されます。提案してください。

Class aspect = urlClsLoader.reloadClass("com.log.LoggingAspect", true, new String("file:"+className));
        com.log.aspect.Aspect aspectObj = (com.log.aspect.Aspect)aspect.newInstance();

それでも私は古いインスタンスを取得しています。

classloader が変更されたクラスをロードしない理由を教えてください。

4

1 に答える 1

2

これは可能ですが、複雑です。あなたがする必要があるURLClassLoaderのは、現在のClassLoaderものを親として新しいものを作成することです。クラスを含むフォルダー (パッケージ フォルダーなし) への URL を新しいフォルダーに追加します。URLClassLoader

loadClass()次に、呼び出す前に新しいクラスを返すようにパッチを適用する必要がありますparent.loadClass()(そうしないと、既存のクラスが使用され、更新されたクラスは無視されます)。

新しいクラスを使用したい場合は複雑になります。このためには、新しいクラスローダーを使用して作成し、すべての人がこのタイプのインスタンスを使用するようにする必要があります。

クラスがWARに存在しない場合は、おそらくより安全です(そしてデバッグが簡単です)。型を使用する代わりに、 を使用してクラスをロードし、URLClassLoaderそのインスタンスを作成します。したがって、このクラスを使用するコードは次のように機能します。

IService service = createService();

whereIServiceは、生成されたクラスがサポートするメソッドを定義するインターフェースです。そうすれば、実際に実装する必要なく、メソッドを使用するコードを書くことができます。

于 2012-09-07T12:14:32.020 に答える