Avatar billede webster Nybegynder
07. oktober 2003 - 16:01 Der er 15 kommentarer og
1 løsning

URLClassLoader cacher object

Hiya

Har været ved at lege lidt med en irc bot og har i den forbindelse fundet det smart at kunne opdatere den mens den kører.

Til det har jeg lavet noget kode der kan indlæse en class ud fra en url. Koden virker fint, problemet er bare at anden gang jeg vil indlæse en fil efter at der er foretaget ændringer, så indlæser den stadigt samme cachede version (filen bliver ændret på hd'en). Jeg går ud fra det har noget at gøre med hvilken class loader URLClassLoader bruger men har ikke kunnet finde en løsning.

Herunder den metode der loader (jeg tester det i en simpel bot til dette formål, derfor den meget grimme opbygning =)

    protected String loadCommandObject(String url, String cName, String cmd){

    try{
        ClassLoader loader = new URLClassLoader( new URL[] { new URL(url)});
        Class loadedClass = loader.loadClass(cName);
       
        Constructor c = loadedClass.getConstructor(new Class[]{ this.getClass()});
        Command newCommand = (Command)c.newInstance(new Object[]{this});

        commands.put(cmd.toLowerCase(), newCommand);
        return "[Loaded " + cmd + " from codebase: " + url + "]";

    }catch (Throwable t){
        System.out.println("Caught throwable. Printing stack trace:");
        t.printStackTrace();

        return "[Error on command load: " + t.getMessage() + "]";
    }

    }
Avatar billede arne_v Ekspert
07. oktober 2003 - 16:14 #1
Når klassen en gang er loadet, så vil den bruges til alle objekter af
den type fremover.

Imidlertid identificeres en klasse af både fuld navn inkl. pakke
og classloader.

Så når du loader med en ny classloader burde du få den nye
klasse loadet.

Hvis (og det er vigtigt !) altså at den classloader bliver brugt til at loade
den med - eller på direkte dansk: de klasser der skal loades må *ikke*
være i classpath (fordi så loades de nemlig af parent classloader !).
Avatar billede webster Nybegynder
07. oktober 2003 - 16:29 #2
jeg har prøvet at haft .class filen til at ligge både lokalt (hvilket muligvis er i classpath, men tror jeg ikke) og på en webserver som helt sikkert ikke er i classpath.. resultatet er det samme. Hvordan skifter jeg lige classloaderen ud? jeg laver jo et nyt URLClassLoader object hver gang og kan ikke lige se hvordan jeg selv kan loade en classloader at give den.
Avatar billede arne_v Ekspert
07. oktober 2003 - 17:10 #3
Et nyt classloader objekt burde være nok.
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:43 #4
Følgende lille spøjse stykke kode virker hos mig:

import java.io.*;
import java.net.*;

public class DoubleDynmaic {
    private static void dynno(int n) {
        (new File("test")).mkdir();
        try {
            OutputStream os = new FileOutputStream("test/Test.java");
            PrintStream ps = new PrintStream(os);
            ps.println("public class Test {");
            ps.println("  public Test() {");
            ps.println("      System.out.println(" + n + ");");
            ps.println("  }");
            ps.println("}");
            ps.close();
            os.close();
            Runtime.getRuntime().exec("javac -d test test/Test.java").waitFor();
            URL[] url = new URL[1];
            url[0] = new URL("file:test/");
            URLClassLoader cl = new URLClassLoader(url);
            Class.forName("Test", true, cl).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        for(int i = 0; i < 10; i++) {
            dynno(i);
        }
    }
}
Avatar billede webster Nybegynder
07. oktober 2003 - 23:08 #5
Jeg kan godt se hvor du vil hen med koden, men når jeg kører den her udskriver den ikke noget overhovedet.. jeg vil lige prøve at implementere din måde i min kode og se hvad der sker
Avatar billede arne_v Ekspert
07. oktober 2003 - 23:10 #6
Hos mig udskriver den 10 linier med tallene 0..9 !
Avatar billede arne_v Ekspert
07. oktober 2003 - 23:10 #7
JDK 1.3.1 og 1.4.1
Avatar billede webster Nybegynder
07. oktober 2003 - 23:18 #8
fik det til at virke, den mappe jeg placerede det i til at teste lå i som undermappe til classpath. Sjovt at den overhovedet ikke skrev noget ud før dog.

Har endnu ikke fået det til at virke med den kode jeg postede først har ændret det til:

    try{
        ClassLoader loader = new URLClassLoader( new URL[] { new URL(url)});
        Class loadedClass = Class.forName(cName, true, loader);
       
        Constructor c = loadedClass.getConstructor(new Class[]{ this.getClass()});
        Command newCommand = (Command)c.newInstance(new Object[]{this});

        commands.put(cmd.toLowerCase(), newCommand);
        return "[Loaded " + cmd + " from codebase: " + url + "]";

    }catch (Throwable t){
        System.out.println("Caught throwable. Printing stack trace:");
        t.printStackTrace();

        return "[Error on command load: " + t.getMessage() + "]";
    }
Avatar billede webster Nybegynder
07. oktober 2003 - 23:22 #9
Tjekkede lige på om classpath kunne være problemet, og ingen af mapperne/parent folders til det her projekt ligger i classpath. Jeg starter programmet op med
java.exe -classpath %CLASSPATH% TestBot

hvor %CLASSPATH% indeholder stien til en række jar filer såsom commons logging og mit irc lib.
Avatar billede webster Nybegynder
07. oktober 2003 - 23:23 #10
programfilerne ligger selvfølgelig også i en af de .jars...
Avatar billede arne_v Ekspert
07. oktober 2003 - 23:26 #11
De klasser der skal loades ligger ikke i de jar filer vel ?
Avatar billede webster Nybegynder
07. oktober 2003 - 23:33 #12
Hehe jo =) Skulle måske overveje at læse hvad du skriver. Skal lige havde afprøvet at det er der problemet stammer fra, men er det sandsynligvis.

Problemet er så at det er noget bøvlet at de ikke må ligge i .jar filen når det jeg nu gerne vil er at kunne opdatere eksisterende filer uden at skulle genstarte den. Kan selvfølgeligt altid lade den loade fra en source der ikke er i classpathen, men virker på en eller anden måde ikke helt korrekt.

Du har mere end fortjent dine point så smid lige et svar =) men du skulle vel ikke vide om man kan omgå denne begrænsning ved at extende ClassLoader og så kalde den protectede defineclass selv med .class filens indhold?
Avatar billede arne_v Ekspert
07. oktober 2003 - 23:36 #13
Jeg mener ikke at du kanundgå at parent classloader loader hvis den kan.

Det har noget med sikkerhed at gøre.
Avatar billede arne_v Ekspert
07. oktober 2003 - 23:37 #14
svar
Avatar billede webster Nybegynder
07. oktober 2003 - 23:42 #15
Nu roder jeg så rundt med at den ikke kan finde filen, men skyldes nok for lidt søvn =) Tak for hjælpen
Avatar billede arne_v Ekspert
08. oktober 2003 - 07:41 #16
Check om du har URL i rigtig syntax.

Det skal enten være URL til en jar-fil eller ende med / for at være
et directory.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester