Rozumiem różnicę między środowiskiem uruchomieniowym i czasem kompilacji oraz jak je rozróżnić, ale po prostu nie widzę potrzeby rozróżniania między zależnościami czasu kompilacji i czasu wykonania.
Ogólne koncepcje czasu kompilacji i środowiska uruchomieniowego compileoraz runtimezależności specyficzne i zakresowe Mavena to dwie bardzo różne rzeczy. Nie można ich bezpośrednio porównywać, ponieważ nie mają one tej samej ramki: ogólne koncepcje kompilacji i środowiska uruchomieniowego są szerokie, podczas gdy koncepcje maven compilei runtimezakresu dotyczą konkretnie dostępności / widoczności zależności w zależności od czasu: kompilacja lub wykonanie.
Nie zapominaj, że Maven to przede wszystkim javac/ javawrapper, a w Javie masz ścieżkę klasy czasu kompilacji, którą określasz, javac -cp ... i ścieżkę klas środowiska wykonawczego, którą określasz java -cp ....
Nie byłoby błędem traktowanie compilezakresu Maven jako sposobu na dodanie zależności zarówno w kompilacji Java, jak iw ścieżce klasy środowiska wykonawczego (javacand java), podczas gdy runtimezakres Maven może być postrzegany jako sposób na dodanie zależności tylko w środowisku wykonawczym Java classppath ( javac).
Dławię się tym: w jaki sposób program może nie zależeć w czasie wykonywania od czegoś, od czego zależał podczas kompilacji?
To, co opisujesz, nie ma żadnego związku runtimeani compilezakresu.
Wygląda na to, że bardziej odpowiada providedzakresowi, który określisz, aby zależność zależała od tego w czasie kompilacji, ale nie w czasie wykonywania.
Używasz go, ponieważ potrzebujesz zależności do kompilacji, ale nie chcesz włączać go do pakietu (JAR, WAR lub innych), ponieważ zależność jest już dostarczona przez środowisko: może być zawarta na serwerze lub w dowolnym ścieżka do ścieżki klasy określonej podczas uruchamiania aplikacji Java.
Jeśli moja aplikacja Java używa log4j, to potrzebuje pliku log4j.jar w celu kompilacji (mój kod integruje się z metodami składowymi i wywołuje je z wnętrza log4j), a także środowiska uruchomieniowego (mój kod nie ma absolutnie żadnej kontroli nad tym, co się stanie, gdy kod wewnątrz log4j .jar jest uruchomiony).
W tym przypadku tak. Ale przypuśćmy, że musisz napisać przenośny kod, który opiera się na slf4j jako fasadzie przed log4j, aby móc później przełączyć się na inną implementację rejestrowania (log4J 2, logback lub dowolną inną).
W tym przypadku w twoim pomie musisz określić slf4j jako compilezależność (jest to ustawienie domyślne), ale określisz zależność log4j jako runtimezależność:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
<scope>runtime</scope>
</dependency>
W ten sposób nie można było odwoływać się do klas log4j w skompilowanym kodzie, ale nadal będzie można odwoływać się do klas slf4j.
Jeśli określisz te dwie zależności z compileczasem, nic nie powstrzyma cię przed odwoływaniem się do klas log4j w skompilowanym kodzie i możesz stworzyć niepożądane sprzężenie z implementacją logowania:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
Typowym zastosowaniem runtimezakresu jest deklaracja zależności JDBC. Aby napisać kod przenośny, nie chcesz, aby kod klienta mógł odwoływać się do klas określonej zależności DBMS (na przykład: zależność PostgreSQL JDBC), ale chcesz, aby to samo zawierało go w aplikacji, ponieważ w czasie wykonywania klasy są potrzebne do API JDBC współpracuje z tym systemem DBMS.