Статьи

Одна банка, чтобы управлять ими всеми

Поездка вниз по переулку памяти

Еще в 1998 году, когда я был разработчиком C / C ++ и пробовал свои силы в Java, некоторые вещи в языке были, мягко говоря, раздражающими для меня. Я помню, волнуюсь об этом довольно много

  1. Почему нет достойного редактора для этого? C / C ++ было немало. Все, что у меня было для Java — старый добрый блокнот.
  2. Зачем мне делать класс, когда все, что я хочу, это функция? Почему функция не была объектом?
  3. Почему я не могу просто упаковать все в один zip / jar и позволить конечному пользователю запустить его двойным щелчком мыши?

и несколько других. В то время я обнаруживал, что часто упрекаю себя за то, что я не могу отказаться от своего «мышления на C / C ++» и придерживаюсь «Java» -го подхода. Теперь, когда мы писали эту статью в 2013 году, спустя полтора десятилетия, неожиданно все эти ранние раздражения исчезли. Не потому, что я принял «Java», а потому, что ява изменилась.

В стороне от пустых разговоров, цель этой статьи — поговорить об одном из этих вопросов: «Почему я не могу просто упаковать все в один zip / jar и позволить конечному пользователю запустить его двойным щелчком мыши?».

Зачем нам это — один zip / jar — это исполняемый файл?

Если вы разработчик, с радостью пишите в своей IDE (я презираю вас всех, кто с самого первого дня запрограммировал java на Eclipse, NetBeans и которому не приходилось кодировать в Notepad), при поддержке Google (я категорически ненавижу всех вас кто не должен был искать что-то в интернете до Google), вероятно, нет убедительного случая.

Однако сталкивались ли вы с ситуацией, когда

  1. Вас втянули в центр обработки данных, потому что парень выполнил ваши шаги по развертыванию, но ваше приложение / веб-сайт просто не будет работать?
  2. Внезапно все переменные среды перепутались, когда «никто вообще так не трогал» производственные блоки, и вы тот, кто должен «просто заставить это работать».
  3. Вы сидите с заинтересованным лицом вашего бизнеса и недоверчиво смотрите на «исключение ClassNotFound» и были уверены, что Java вам совсем не понравилась.

Короче говоря, я пытаюсь сказать, что, когда вы находитесь в «относительном» здравомыслии своей коробки / среды разработки, один исполняемый файл jar на самом деле ничего не делает для вас. Но в тот момент, когда вы входите в сумеречную зону неизвестных серверов и ситуаций (без IDE и другого ассортимента инструментов), вы начинаете понимать, насколько мог помочь один исполняемый файл jar.

Хорошо, я понимаю. Но в чем дело? Мы можем сделать такой пакет / zip / jar в один миг, если потребуется. Не правда ли?

Во всей своей наивности я так и думал и выяснил ответ трудным путем. Позволь мне провести тебя через это. Зажги своих редакторов. Давайте создадим исполняемый проект Jar. Я использую jdk1.7.0, STS, Maven 3.0.4. Если вы новичок в Maven или просто не в руки, я рекомендую вам прочитать
это и это

Файл: C: \ projects \ MavenCommands.bat

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
ECHO OFF
REM =============================
REM Set the env. variables.
REM =============================
SET PATH=%PATH%;C:\ProgramFiles\apache-maven-3.0.4\bin;
SET JAVA_HOME=C:\ProgramFiles\Java\jdk1.7.0
REM =============================
REM Standalone java application.
REM =============================
call mvn archetype:generate ^
-DarchetypeArtifactId=maven-archetype-quickstart ^
-DinteractiveMode=false ^
-DgroupId=foo.bar ^
-DartifactId=executableJar001
pause

После запуска этого пакетного файла у вас будет полностью компилируемое стандартное Java-приложение. Продолжайте, скомпилируйте его и соберите jar (mvn -e clean install). В итоге вы получите исполняемый файл Jar001-1.0-SNAPSHOT.jar по адресу C: \ projects \ executetableJar001 \ target. Теперь поехали
java -jar jarFileName ‘. И вот ты споткнулся в первый раз. В словаре geeky он говорит вам, что не было класса с основным методом, и, следовательно, он не знал, что выполнять. К счастью, это легко. Есть стандартный процесс Java, чтобы решить это. И есть плагин Maven, чтобы решить это. Я буду использовать последний.

Обновленный файл: /executableJar001/pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
 <dependencies>
 ...
 </dependencies>
 
 <build>
  <plugins>
   <!-- Set main class in the jar. -->
   <plugin>
    <groupid>org.apache.maven.plugins</groupid>
    <artifactid>maven-jar-plugin</artifactid>
    <version>2.4</version>
    <configuration>
     <archive>
      <manifest>
       <mainclass>foo.bar.App</mainclass>
      </manifest>
     </archive>
    </configuration>
   </plugin>
 
  </plugins>
 </build>
 ...

Вы можете снова скомпилировать и собрать приложение (mvn -e clean install). Это создаст файл JAR в целевой папке. Попробуйте запустить банку из командной строки еще раз. На этот раз вы получите желаемый результат. Итак, мы все отсортированы, верно? Неправильно. Очень неправильно.

Почему? Все вроде нормально.

Давайте углубимся немного глубже и выясним, почему все не так отсортировано, как кажется на данный момент. Давайте продолжим и добавим зависимость, например, скажем, мы хотим добавить ведение журнала и для этого мы хотим использовать сторонний jar, т.е. logback. Я позволю Maven обрабатывать зависимости в среде разработки.

Обновленный файл: /executableJar001/pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
...
 <dependencies>
  <!-- Logging -->
  <dependency>
   <groupid>ch.qos.logback</groupid>
   <artifactid>logback-classic</artifactid>
   <version>1.0.9</version>
  </dependency>
  
 </dependencies>
 
 <build>
  ...
 </build>

Обновленный файл: /executableJar001/src/main/java/foo/bar/App.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package foo.bar;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class App
{
 private final static Logger logger = LoggerFactory
   .getLogger(App.class);
 
    public static void main( String[] args )
    {
        System.out.println( 'Hello World!' );
        logger.debug('Hello world from logger.');
    }
}

Теперь давайте скомпилируем и запустим jar из командной строки, используя команду jar. Вы видели, что случилось?

1
Exception in thread 'main' java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

В основном это говорит о том, что класс (то есть фактический код) LoggerFactory (то есть сторонний jar, который мы добавили в среду разработки) не был найден.

Да, но мы должны сказать java, что нужно брать сторонние библиотеки из какой-то папки.

Определенно. Это почти наверняка — если вы задаете этот вопрос — что для большинства ваших приложений вы сообщаете JVM, где находятся сторонние библиотеки / библиотеки зависимостей. Вы говорите это, устанавливая classpath. Возможно, вы могли бы использовать какой-нибудь сервер приложений, например Tomcat / Jetty, и он мог бы сам собирать некоторые зависимости. И это именно то, где проблема возникает.

Как разработчик, я предоставляю x.jar, который работает. Однако, чтобы это работало, это зависит от a.jar (что, в свою очередь, может зависеть от b.jar и c.jar … вы поймете точку). Когда я, как разработчик, связываю свой результат, x.jar, возникает зависимость — от того, кому я передаю это, — чтобы убедиться, что путь к классам правильно установлен в другой среде, где предполагается x.jar работать.

В основном это не так уж важно. Впрочем, это тоже не тривиально. Существует множество способов испортить зависимости от целевой среды. Там могут быть обычные обновления. Возможно, в этом же рабочем ящике было развернуто какое-то другое приложение, для которого требовалось обновить банку, и никто не думал, что она повлияет на вашу. Мы можем обсудить и обсудить множество способов, как можно предотвратить подобные неудачи, но суть в том, что x.jar (ответственность разработчика) имеет зависимости (которые разработчик не контролирует напрямую). И это приводит к неудачам.

Конечно, если вы добавите в эту смесь множество переменных, которые появляются из-за разных версий, разных серверов приложений и т. Д. И т. Д., Существующее решение предоставления только x.jar быстро станет очень хрупким.

Так что же нам делать?

Скажите спасибо доктору П. Саймону Таффсу . Этот джентльмен объясняет, как он решил эту проблему в этой ссылке . Это хорошее чтение, я рекомендую его. То, что я объяснил очень мирянски (и едва поцарапал поверхность), Саймон глубоко погрузился в проблему и то, как он ее решил. Короче говоря, он закодировал решение и сделал его открытым исходным кодом . Я не собираюсь повторять ту же самую информацию снова — прочитайте его статью , она довольно информативна — но я назову существенную точку его решения.

  1. Это позволяет людям создать единую банку, которая содержит все — ваш код, ресурсы, зависимости, сервер приложений (потенциально) — все.
  2. Это позволяет конечному пользователю запускать весь этот огромный jar с помощью простой команды java -jar jarFileName.
  3. Это позволяет разработчикам развиваться так же, как они разрабатывали, например, если это веб-приложение, структура файла war остается прежней. Так что никаких изменений в процессе разработки нет.

Хорошо. Так как же нам это сделать?

Есть много мест, где это детализировано. Сайт One-JAR . Муравей с одной банкой . Maven с одной банкой .

Давайте посмотрим это в действии на нашем фиктивном коде. К счастью, для этого есть также плагин Maven . К сожалению, этого нет в репозитории Maven Central (Почему? Ребята, почему? Вы вложили 98% работы. Зачем быть вялым в отношении последних 2%?). Это идет с хорошим
инструкция по применению .

Обновленный файл: /executableJar001/pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
  
 <dependencies>
  ...
 </dependencies>
 
 <build>
  <plugins>
    
   ...
 
   <!-- If you wanted to bundle all this in one jar. -->
   <plugin>
    <groupid>org.dstovall</groupid>
    <artifactid>onejar-maven-plugin</artifactid>
    <version>1.4.4</version>
    <executions>
     <execution>
      <goals>
       <goal>one-jar</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
  
 <!-- Required only if you are usng onejar plugin. -->
 <pluginrepositories>
  <pluginrepository>
   <id>onejar-maven-plugin.googlecode.com</id>
  </pluginrepository>
 </pluginrepositories>

Теперь все, что вам нужно сделать, это запустить mvn -e clean package. Вы получите, кроме обычной банки, банку с полным самодостаточностью. Продолжайте, снова выполните команду java -jar jarFileName из командной строки. Он должен работать.

Хм .. это звучит хорошо. Почему не все идут на это? И этот One-JAR, кажется, существует с 2004 года. Почему мы не видим больше игроков на этом рынке?

Вы знаете, что они говорят о бесплатных обедах? Там нет ни одного. Хотя концепция довольно изящная и очень практичная, это не означает, что все остальные игроки решили присоединиться. Поэтому, если ваш веб-сайт «нуждается» в размещении на одном из платных серверов приложений Biggie (я не знаю, почему вы хотите продолжать платить за эти проприетарные программы и людей, которые их понимают. Если вы не платите только за качественных людей и полагаетесь на приложения с открытым исходным кодом, которые не блокируют вас) One-JAR может оказаться нереальным решением для вас. Кроме того, я слышу неподтвержденные слухи о том, как все может стать вялым (во время загрузки, если ваше приложение велико. Поэтому, прежде чем вы решите использовать это, я рекомендую вам сделать POC и убедиться, что другие биты вашего стека техподдержки не недоволен One-JAR.

Мое личное мнение, что 2004 год был, пожалуй, слишком рано для такого рода вещей. Люди все еще боролись с такими вещами, как стандартизация процесса сборки и выпуска, получение чистого проигрывателя в области ORM, закрытие прозрачного проигрывателя для среды MVC и т. Д. Не то, чтобы на эти вопросы уже отвечали, или они скоро появятся. Но я думаю, что вкус текущих проблем в мире ИТ вокруг

  1. Как заставить DevOps работать.
  2. Как сделать всю сборку и выпуск автоматизированными.
  3. Как использовать библиотеки с открытым исходным кодом для обеспечения надежного программного обеспечения, при этом гарантируя, что нет тяжелого проприетарного программного обеспечения, вызывающего блокировку, и, следовательно, сделать решение менее гибким для будущих бизнес-требований.

И, на мой взгляд, One-JAR очень хорошо играет в этой области. Итак, я определенно ожидаю увидеть больше этого инструмента и / или большего количества инструментов вокруг этой концепции. И, честно говоря, в этой области больше игроков. Спасибо Кристиану Шлихтерле за указание на это. Есть Maven Assembly Plugin и Maven Shade Plugin, которые обслуживают эту точно такую ​​же проблему. Я еще не пробовал их, но из документации они выглядят вполне нормально, по характеристикам. Dropwizard хоть и не одно и то же, но по сути очень похож. Они расширили концепцию всего одного jar со встроенным сервером приложений, встроенную поддержку REST, JSON, Logback, вроде приятного аккуратного пакета, который вы можете просто использовать прямо с полки.

Так что, как я повторяю, это хорошие захватывающие времена в технологическом бизнесе, особенно если вам нравится возиться с программным обеспечением.

Ссылка: одна банка, чтобы управлять ими всеми, от нашего партнера JCG Partho в блоге Tech for Enterprise .