JDK, JRE, JVM — Java: Настройка окружения
JVM (Java Virtual Machine) — Виртуальная машина отвечает за само выполнение кода. Она работает с байткодом (тем, что находится внутри файлов с расширением .class).
JRE (Java Runtime Environment) — окружение, необходимое для запуска Java-программ. Включает в себя стандартную библиотеку. В нее входят, как базовые пакеты lang, util, так и пакеты для работы с различными форматами, базами данных, пользовательским интерфейсом. JVM тоже часть JRE.
JDK (Java Development Kit) — набор программ для разработки. Именно его мы (или редактор) устанавливаем к себе на компьютер, чтобы заниматься разработкой на Java. Он включает в себя JRE, загрузчик кода java, компилятор javac, архиватор jar, генератор документации javadoc и другие утилиты, нужные во время разработки.
Write once, run anywhere
Java — компилируемый язык. Обычно, когда говорят про такие языки, подразумевают, что компилятор берет исходный код и превращает его в машинный код, заточенный под конкретную архитектуру (машинный код у разных архитектур разный) и операционную систему. Так происходит во многих си-подобных языках. На выходе получаются файлы, каждый из которых может запуститься только на своей комбинации архитектуры и операционной системы.
# Компиляция Go программы для двух разных комбинаций GOOS=linux GOARCH=arm go build path/to/file GOOS=windows GOARCH=amd64 go build path/to/file
Для запуска таких программ больше ничего не нужно. Достаточно перенести их на нужную систему и запустить штатными средствами. Такие программы работают очень быстро, так как оптимизированы под конкретные условия.
# Запуск на Windows hexlet.exe
Java устроена по-другому. Разработчики попытались обеспечить кроссплатформенность готовой программы, за счет введения виртуальной машины. Кроссплатформенность, способность программы запускаться на разных платформах (архитектура процессора и операционная система) без необходимости компилировать код под эти системы. Как это работает?
Ядро Java это JVM. Виртуальный процессор, со своим набором команд, который придумали создатели Java. Компилятор готовит код именно под эту единую JVM. Например, код:
for (int i = 2; i 1000; i++) for (int j = 2; j i; j++) if (i % j == 0) continue outer; > System.out.println (i); >
После компиляции превращается в:
JVM выполняет байткод построчно и транслирует его в реальный машинный код, специфичный для той архитектуры, на которой он запускается.
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Основы работы Spring: аннотация @Configuration
Аннотация @Configuration является частью основной структуры фреймворка Spring. Она указывает, что класс содержит методы определения @Bean. Таким образом, контейнер Spring может обрабатывать класс и генерировать Spring Beans, которые можно использовать в приложении.
Как работает @Configuration
@Configuration позволяет нам использовать аннотации для внедрения зависимостей. Давайте разберемся, как создавать классы конфигурации Spring.
Давайте создадим простой класс java bean.
package com.journaldev.spring; public class MyBean < public MyBean() < System.out.println("MyBean instance created"); >>
Прежде чем использовать какой-либо из классов фреймворка Spring, нам нужно добавить его зависимости в проект.
org.springframework spring-context 5.0.6.RELEASE
Теперь давайте создадим класс Configuration.
package com.journaldev.spring; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyConfiguration < @Bean public MyBean myBean() < return new MyBean(); >>
Затем мы напишем простой класс и настроим наш configuration класс Spring.
package com.journaldev.spring; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MySpringApp < public static void main(String[] args) < AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(MyConfiguration.class); ctx.refresh(); // MyBean mb1 = ctx.getBean(MyBean.class); // MyBean mb2 = ctx.getBean(MyBean.class); ctx.close(); >>
Если вы запустите приложение, которое мы создали выше, оно выдаст следующий результат:
May 23, 2018 12:34:54 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@ff5b51f: startup date [Wed May 23 12:34:54 IST 2018]; root of context hierarchy MyBean instance created May 23, 2018 12:34:54 PM org.springframework.context.support.AbstractApplicationContext doClose INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@ff5b51f: startup date [Wed May 23 12:34:54 IST 2018]; root of context hierarchy
Обратите внимание: Spring загружает bean-компоненты в свой контекст еще до того, как мы его запросили. Это делается для того, чтобы убедиться, что все bean-компоненты правильно настроены, а приложение будет работать быстро, если что-то пойдет не так. Также необходимо вызвать ctx.refresh(), иначе мы получим следующую ошибку, если попытаемся извлечь из контекста любой компонент.
Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@f0f2775 has not been refreshed yet at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1076) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1106) at com.journaldev.spring.MySpringApp.main(MySpringApp.java:11)
Если вы раскомментируете операторы, в которых мы извлекаем экземпляры MyBean, вы заметите, что он не вызывает конструктор MyBean. Это связано с тем, что областью действия bean-компонентов в Spring по умолчанию является Singleton. Мы можем изменить эту область с помощью аннотации @Scope.
Что, если мы удалим аннотацию @Configuration?
Давайте посмотрим, что произойдет, если мы удалим аннотацию @Configuration из класса MyConfiguration.
Класс будет по-прежнему работать так, как ожидалось, а bean-компоненты будут регистрироваться и извлекаться как одноэлементные классы. Но если в этом случае мы вызовем метод myBean(),то у нас получится простой вызов метода Java, в результате чего мы извлечем новый экземпляр MyBean, который не будет одноэлементным. Чтобы доказать это, давайте определим другой компонент, который будет использовать экземпляр MyBean.
Configure java что это

Установка и настройка Java
Установка и
настройка Java (ч. 2)
В предыдущей части мы написали простую программу с помощью онлайн-редактора кода. Если хотите, можете им пользоваться какое-то время. Но рано или поздно придется идти дальше в познании Java и сопутствующих технологий. А для этого уже нужны совсем другие инструменты. О некоторых из них мы и поговорим в этой статье.
Для того чтобы начать писать приложения на Java у себя на компьютере, требуется выполнить подготовительную работу, связанную с установкой и настройкой необходимых программ.
1. Написано однажды, работает везде
Java — это не просто язык. Это целая платформа, экосистема, состоящая из набора инструментов для разработчиков и разных подсистем. При этом Java является кроссплатформенным языком.
Под платформой обычно понимают сочетание аппаратной (процессор) и программной (операционная система, ОС) части.
В предыдущей статье наша маленькая программка выводила фразу: «Write once, run anywhere». Это девиз Java, подчеркивающий ее платформонезависимость.
Раньше приложения писали под конкретную ОС. Это означало, что перенести их с одной ОС на другую было крайне проблематично. Приходилось под каждую из них создавать чуть ли не с нуля новую версию программы. Зачастую под каждую платформу нанимали новую команду разработчиков. Это трудозатратно и выходит намного дороже по стоимости.
В какой-то момент возникла идея сделать универсальную платформу, на которой могли бы работать приложения, написанные под разные ОС.
Для реализации этой задумки была создана виртуальная машина (Java Virtual Machine, JVM). Это специальное приложение, которое позволяет запускать программы, написанные на Java, на любой ОС и любом железе (при условии, что JVM реализована для используемой платформы).
Виртуальная машина является прослойкой между процессором и программным кодом. При этом она запускает не файлы с исходным кодом (с расширением .java), а специальные промежуточные файлы с расширением .class в которых хранится байт-код. Этот код назван так из-за того, что представляет собой набор команд в один байт, хотя имеются команды и большей длины.
В использовании байт-кода и заключается магия переносимости программ с одной ОС на другую без внесения каких-либо изменений.
Чтобы из исходного файла получить файл, понятный JVM, его нужно скомпилировать.
Компиляция — это процесс преобразования кода, написанного на языке программирования, например, Java в специальный код, который компьютер (в нашем случае JVM) может понять и запустить. Для компиляции используется программа под названием компилятор.
Все виртуальные машины, неважно на какой ОС они установлены, знают и понимают байт-код одинаково хорошо, т. к. он представляет собой не машинные команды конкретной компьютерной платформы (конкретного процессора в виде последовательности нулей и единиц), а команды JVM. За счет этого и реализуется кроссплатформенность. Промежуточный код не зависит от какой-то ОС или процессора, т. к. не содержит код, созданный специально под них. Он содержит байт-код, который одинаково интерпретируется JVM на любой платформе.
Конфигурация Java систем — как убрать боль

Если вы хотя бы однажды разрабатывали большую систему на Java и сопровождали её, то, наверняка, сталкивались с неудобствами настройки тех или иных процессов в системе.
А именно: размеры различных буферов; параметры почтового ящика; хост, порт, логин, пароль вызова внешних сервисов; всякие таймауты и многое другое.
Каждый раз менять всё это в коде, пересобирать и перенакатывать на реал — не комильфо.
Естественно все эти параметры нужно выносить в файлы конфигов и считывать их оттуда — все так делают.
В Java из коробки для этого есть некий Properties. Но пользоваться им крайне неудобно. Во-первых, UTF-8 там не работают, во-вторых — если вы поменяли какой-нибудь параметр в конфиге, то чтобы новое значение попало в систему — требуется перезапуск приложения. А если вы не хотите его перезапускать, или это невозможно в 11 утра — час пиковой нагрузки. И отложить на потом не вариант — нужно срочно. Что делать? Нужно чтобы конфиги перечитывались на «горячую», т. е. без перезапуска системы.
А ещё очень важно: нужно как-то так придумать чтобы имена параметров конфигов в коде программы соответствовали тем, которые в файле. Т. е. чтобы трудно было ошибиться. Обычно используют для этого константы — помогает, но хотелось бы что-то удобнее, проще и гибче.
И вот ещё что: представьте у вас крупная система в которой уже накопилось около тридцати конфигурационных файлов, и в каждом по десятку параметров. И вам нужно накатить новую инстанцию. Как вы будете настраивать эти конфиги? Создавать каждый вручную? В каждом прописывать имена параметров и их значения, вспоминая что каждый из них значит? А если забыли? А есть документация? А эта документация актуальная? А если вы ошибётесь в одной буковке параметра — позволит ли вам система при старте сразу объяснить что не так? Или она свалится в час ночи, когда вы крепко спите? Вам придётся просыпаться, включать как-то мозг и разбираться во всей этой истории…
Хотелось бы избежать всей этой нервотрёпки.
Надо как-то сделать так, чтобы система создавала все эти конфиги сама, и описывала их всех — что каждый конфиг делает в общем, и каждый параметр в частности. Ну и разработчик не должен сильно напрягаться чтобы поддерживать всю эту автоматизацию в актуальном состоянии.
Всё это должно быстро и легко активироваться — подключил какую-то маленькую библиотечку, прописал какой-то магический код размером не больше пяти-десяти строк (автосгенерированные вашей IDE строки не считаем) — и вуаля — всё работает.
Можно конечно использовать конфигурационный сервер, и даже кто-то это делает (вроде), но это как-то напряжно — хочется что-нибудь проще, но эффективно.
Мы в greetgo! поискали в разных интернетах, но так ничего подходящего не нашли — пришлось пилить самим.
Решение
Основной идеей было использовать Java-интерфейс для чтения данных конфига, и, одновременно, формирования структуры конфига. Вы один раз в интерфейсе написали имя метода — и это имя автоматически становится именем параметра в конфиге. Вам не нужно его писать второй раз в файле конфига, опасаясь допустить ошибку в одной букве — файл пусть создаётся автоматически со всеми параметрами — вам нужно будет только подкорректировать значения параметров.
Например вы хотите вынести в конфиг updateTimeout и batchSize — потому что трудно их подобрать изначально. Для этого создаёте Java-интерфейс:
public interface MyMigrationConfig
Хотя вот так будет лучше:
@Description("Миграция состояний в ядро системы"); public interface MyMigrationConfig
Теперь этот интерфейс надо зарегистрировать в какой-то классной штуке, которая умеет автоматически создавать магические реализации подобных интерфейсов, и после этого пользоваться, например, таким способом:
@Autowire private MyMigrationConfig config; public void migrate() < // . System.out.println(" updateTimeoutMs = " + config.updateTimeoutMs()); System.out.println(" batchSize https://github.com/greetgo/greetgo.conf" rel="noopener noreferrer nofollow">https://github.com/greetgo/greetgo.confПодключив её к проекту, необходимо создать фабрику конфигов примерно так:
public class MyConfigFactory extends FileConfigFactory < @Override public Path getBaseDir() < return Paths.get("/path/to/directory/where/config/files/are/located"); >@Override protected String getConfigFileExt() < return ".conf"; >>
Дальше создаём инстанцию этой фабрики и пользуемся магическим методом createConfig:
MyConfigFactory confFactory = new MyConfigFactory(); MyMigrationConfig config = confFactory.createConfig(MyMigrationConfig.class);
Теперь у нас есть инстанция интерфейса конфига и мы можем считывать данные конфига. Они будут считываться из файла с именем MyMigrationConfig.conf. Этот файл создастся автоматически, если его ещё нет, с примерно таким содержимым:
# Created at 2021-01-29 11:03:21 # Миграция состояний в ядро системы # Размер порции мигрируемых данных batchSize=150 # Максимальное время миграции одной порции в миллисекундах. Если оно будет # превышено, то миграция будет немедленно прервана с ошибкой updateTimeoutMs=30000
Теперь вы можете менять эти параметры и система автоматически их будет перечитывать. Естественно про оптимизацию мы подумали — всё это внимательно кэшируется, и, если вы будете очень часто считывать параметры (тысячи раз в секунду), то это не вызовет большую нагрузку на файловую систему.
Возможности
Со временем у нас появились распределённые проекты с большим количеством нод и с использованием kubernetes. Хранить настройки в файлах в таких проектах оказалось не удобно, и мы сделали расширение библиотеки, которое позволяет хранить настройки в Zookeeper, для этого нужно просто заменить FileConfigFactory на AbstractZookeeperConfigFactory, ну и прописать параметры доступа к Zookeeper.
Также есть реализация JdbcConfigFactory — которая позволяет хранить настройки в реляционной БД.
Архитектура библиотеки позволяет достаточно просто разрабатывать свои фабрики конфигов, например чтобы хранить конфиги в яндекс-диске.
Также есть возможность использовать аннотацию @FirstReadEnv — которая считывает помеченный ей параметр не из конфига, а из переменной окружения — в kubernetes некоторые параметры удобнее задавать через переменные окружения.
На этом все. Спасибо за внимание.