Java for Beginner
742 subscribers
708 photos
196 videos
12 files
1.14K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
🗓 История IT-технологий сегодня — 3 сентября


ℹ️ Кто родился в этот день

Андрей Николаевич Терехов (3 сентября 1949, Ленинград — 31 июля 2025)советский и российский учёный в области информатики, доктор физико-математических наук, профессор, заведующий кафедрой системного программирования Санкт-Петербургского государственного университета.


🌐 Знаковые события

1880 в Петербурге инженер Фёдор Пироцкий продемонстрировал первый в России (по некоторым сведениям — первый в мире) электрический трамвай.

1976 — посадка космического аппарата Viking 2 на Марсе. NASA завершает посадку на Марс в рамках миссии Viking 2; зонд передал первые цветные снимки планеты.

1982 — начало фестиваля US Festival. Мероприятие, организуемое Стивом Возняком, сочетало музыку и технологические выставки (новейшие видеоигры, компьютерные демо), стало заметным культурно-техно событием.


#Biography #Birth_Date #Events #03Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Основы ООП в Java

Глава 4. Полиморфизм

instanceof и приведение типов

В полиморфизме ссылка суперкласса или интерфейса может указывать на объект подкласса, но статический тип ссылки ограничивает доступ только к методам суперкласса. Чтобы получить доступ к методам подкласса или проверить тип, используются приведение типов и instanceof.

Приведение типов (Casting): Это преобразование ссылки одного типа в другой.

В Java:
Upcasting: Автоматическое приведение к суперклассу или интерфейсу (безопасно).
Downcasting: Явное приведение к подклассу (рискованно, может вызвать ошибку на runtime).


instanceof: Оператор, проверяющий на runtime, является ли объект экземпляром класса, подкласса или реализатором интерфейса. Возвращает boolean.

Это инструменты для безопасной работы с полиморфизмом: сначала проверка instanceof, затем downcasting.


Приведение типов: Upcasting и Downcasting

Upcasting: Автоматическое, безопасное. Ссылка подкласса преобразуется в суперкласс или интерфейс.
Почему: Для полиморфизма — общий код работает с разными объектами.
Нюанс: После upcasting доступны только методы суперкласса.


Пример:
Dog dog = new Dog("Шарик");
Animal animal = dog; // Upcasting: Dog → Animal (автоматически)
animal.makeSound(); // Вызывает версию Dog (полиморфизм)

Здесь animal — тип Animal, но объект Dog.


Downcasting: Явное, с риском. Используйте (Type) перед ссылкой.
Почему: Чтобы получить доступ к методам подкласса через ссылку суперкласса.
Риск: Если объект не того типа — ClassCastException на runtime.


Пример:
Animal animal = new Dog("Шарик");  // Upcasting
Dog dog = (Dog) animal; // Downcasting: Animal → Dog
dog.bark(); // Доступен метод Dog

Работает, потому что объект действительно Dog.


Нюанс: Без проверки:
Animal animal = new Cat("Мурка");
Dog dog = (Dog) animal; // ClassCastException: Cat cannot be cast to Dog



#Java #для_новичков #beginner #poliphormizm #instanceof #Upcasting #Downcasting
👍5
Оператор instanceof: Проверка типа

instanceof проверяет совместимость типов на runtime.

Синтаксис:
object instanceof Type

Возвращает true, если объект является экземпляром Type (класс, интерфейс) или его подтипа.


Нюанс: Для null — всегда false.

С Java 14+: Pattern matching (instanceof с переменной), но для простоты используем классический.

Пример безопасного downcasting:
Animal animal = new Dog("Шарик");

if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // Безопасно
} else {
System.out.println("Не собака!");
}

Проверка предотвращает ClassCastException.


С интерфейсами:
SoundMaker sound = new Dog("Шарик");
if (sound instanceof SoundMaker) { // true
// ...
}


Нюансы instanceof:
Работает с классами, интерфейсами, массивами.
Для примитивов — нет (они не объекты).
В иерархии: Dog instanceof Animal — true; Animal instanceof Dog — false (если объект Animal).
Performance: Не дорогой, но избегайте в горячих циклах.
Альтернативы: getClass().equals(Class.class) — строже, не учитывает подтипы.



Полный пример с полиморфизмом

Используем Animal, Dog, Cat:
public class Main {
public static void main(String[] args) {
Animal[] animals = {new Dog("Шарик"), new Cat("Мурка"), new Animal("Зверь")};

for (Animal a : animals) {
a.makeSound(); // Полиморфизм: каждый свой звук

if (a instanceof Dog) {
Dog d = (Dog) a;
d.bark(); // Только для Dog
} else if (a instanceof Cat) {
Cat c = (Cat) a;
// Специфический метод Cat, если есть
}
}
}
}

Цикл работает с массивом Animal, но проверяет и приводит для специфического поведения.


Нюансы

ClassCastException
: Всегда проверяйте instanceof перед downcasting.
Null: null instanceof Type — false; (Type) null — null (без исключения).
Generics: instanceof не работает с параметризованными типами на runtime (type erasure).
Массивы: Object[] instanceof String[] — false, даже если элементы String.
Интерфейсы: Класс может реализовывать несколько — instanceof true для любого.
Final классы: Не влияет на instanceof.
Performance и дизайн: Избегайте чрезмерного использования instanceof — это признак плохого дизайна (лучше полиморфизм через overriding). Используйте, когда нужно специфическое поведение.
Java 14+ Pattern Matching: if (animal instanceof Dog d) { d.bark(); } — упрощает, но для совместимости используйте классику.



Как создать это в IntelliJ IDEA

Проверка instanceof: IDE подскажет автодополнение.
Генерация: После if (a instanceof Dog) { } — IDE предложит создать переменную.
Debug: Поставьте breakpoint и смотрите типы объектов.



Полезные советы для новичков

Всегда проверяйте перед cast: Избегайте runtime ошибок.
Предпочитайте overriding: Вместо instanceof + cast, переопределяйте методы.
В коллекциях: Полезно для фильтрации типов.


#Java #для_новичков #beginner #poliphormizm #instanceof #Upcasting #Downcasting
👍3
Что выведет код?

public class Task030925 {
public static void main(String[] args) {
Object obj = "Hello";

if (obj instanceof Integer) {
Integer num = (Integer) obj;
System.out.println(num + 10);
} else if (obj instanceof String str) {
System.out.println(str.length());
} else {
System.out.println("Unknown");
}
}
}


#Tasks
👍1
Варианты ответа:
Anonymous Quiz
64%
5
9%
15
18%
"Unknown"
9%
ClassCastException
👍1
Вопрос с собеседований

Что такое WatchService в Java? 🤓

Ответ:

WatchService
(java.nio.file) мониторит изменения в файловой системе.

Пример:
WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Paths.get(".");
dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
WatchKey key = watcher.take();

Полезен для файловых наблюдателей.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🗓 История IT-технологий сегодня — 4 сентября


ℹ️ Кто родился в этот день

Джон Маккарти (англ. John McCarthy; 4 сентября 1927, Бостон — 24 октября 2011, Стэнфорд) — американский информатик, автор термина «искусственный интеллект» (1956), изобретатель языка Лисп (1958), основоположник функционального программирования, лауреат премии Тьюринга (1971) за огромный вклад в область исследований искусственного интеллекта.

Карле́н Ара́мович Абгаря́н (4 сентября 1928, Амасия, Ленинаканский уезд — 4 февраля 1995, Санкт-Петербург) — советский учёный в области технической кибернетики/автоматизации и робототехники.


🌐 Знаковые события

1837в Нью-Йоркском университете Сэмюэл Морзе впервые продемонстрировал своё изобретение — телеграф.

1882в Нью-Йорке Томас Эдисон запустил первую в мире центральную электростанцию и впервые в истории включил коммерческое электрическое освещение (всего для 85 платных клиентов).

1964в Шотландии официально открыт Форт-Роуд-Бридж.

1998 — официальное учреждение (регистрация/основание) Google. Ключевая веха истории поисковых систем и дальнейшего развития веб-экосистемы.


#Biography #Birth_Date #Events #04Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Основы ООП в Java

Глава 5. Абстракция

Абстрактные классы и методы

Абстракция — это принцип ООП, который упрощает сложные системы, скрывая ненужные детали и показывая только essential интерфейс. Это позволяет моделировать реальные концепции на высоком уровне: например, "автомобиль" как абстракция, где вы знаете, что он едет, но не вникаете в механику двигателя.

В Java абстракция реализуется через абстрактные классы и интерфейсы (интерфейсы подробнее в следующем уроке). Абстрактные классы предоставляют частичную реализацию, заставляя подклассы заполнить пробелы.
Абстрактные классы: Определение и использование


Абстрактный класс — это класс, помеченный ключевым словом abstract, который нельзя инстанцировать (new AbstractClass() — ошибка). Он служит шаблоном для подклассов, предоставляя общий код и требуя реализации специфических частей.

Синтаксис:
public abstract class AbstractClass {
// Абстрактные методы, concrete методы, поля
}


Особенности:
Может иметь абстрактные методы (без тела).
Может иметь обычные (concrete) методы с реализацией.
Может иметь поля, конструкторы.
Подклассы должны extends абстрактный класс и реализовать все абстрактные методы (или сами стать abstract).
Нюанс: Абстрактный класс может не иметь абстрактных методов — просто для предотвращения инстанциации.


Пример абстрактного класса Shape (Фигура):
public abstract class Shape {
protected String color; // Общее поле

public Shape(String color) {
this.color = color;
}

// Абстрактный метод: Подклассы должны реализовать
public abstract double getArea();

// Concrete метод: Общий для всех
public void displayColor() {
System.out.println("Цвет: " + color);
}
}

getArea(): Абстрактный — без тела, заканчивается ;.
displayColor(): С реализацией — наследуется как есть.



#Java #для_новичков #beginner #Abstract
👍4
Абстрактные методы: Требование реализации

Абстрактный метод — это метод без тела, помеченный abstract. Он определяет "что делать", но не "как".

Синтаксис:
public abstract returnType methodName(params);


Правила:
Может быть только в абстрактном классе или интерфейсе.
Нет тела — только сигнатура.
Подклассы должны override и реализовать (или стать abstract).
Модификаторы: Не может быть private (бесполезно, если не виден), final (нельзя override), static (static не override).


Подкласс Circle, реализующий Shape:
public class Circle extends Shape {
private double radius;

public Circle(String color, double radius) {
super(color); // Вызов конструктора абстрактного класса
this.radius = radius;
}

// Реализация абстрактного метода
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}

Circle не abstract, так что обязан реализовать getArea().
Теперь можно new Circle(...), но не new Shape().


Полиморфизм с абстрактными классами

Абстрактные классы усиливают полиморфизм: ссылка на абстрактный класс может указывать на concrete подклассы.


Пример:
public class Main {
public static void main(String[] args) {
Shape shape = new Circle("Красный", 5.0); // Полиморфизм: Shape на Circle
shape.displayColor(); // Цвет: Красный (concrete метод)
System.out.println("Площадь: " + shape.getArea()); // Площадь: ~78.54 (реализация Circle)
}
}

Нюанс: Конструктор абстрактного класса вызывается через super(), даже если класс abstract.



Все нюансы абстрактных классов и методов

Инстанциация
: new AbstractClass() — ошибка компиляции.
Конструкторы: Могут быть, вызываются super() из подклассов. Полезны для инициализации общих полей.
Поля: Могут быть final, static, private и т.д. Static поля/методы доступны через AbstractClass.field.
Наследование: Абстрактный класс может extends другой abstract или concrete класс.
Интерфейсы vs abstract классы: Abstract классы могут иметь реализацию и состояние; интерфейсы — нет (до Java 8). Abstract для "is-a" с частичной реализацией.
Ошибки:
Абстрактный метод в non-abstract классе — ошибка.
Не реализован abstract метод в concrete подклассе — ошибка.
Abstract метод с телом — ошибка.

Модификаторы: Abstract класс не может быть final (final не extends). Abstract метод не может быть final/static/private.
Дизайн: Используйте для шаблонов с общим кодом, где подклассы уточняют поведение. Избегайте глубоких иерархий.
Java-специфика: С Java 8 интерфейсы имеют default методы, размывая грань с abstract классами.



Как создать это в IntelliJ IDEA

Абстрактный класс: New → Java Class → Укажите abstract в коде, или IDE предложит.
Абстрактный метод: В abstract классе напишите abstract void method(); — IDE подскажет.
Реализация: В подклассе Ctrl+O (Override) — выберите abstract метод.
Проверка: Если не реализован — IDE выделит ошибку.



Полезные советы для новичков

Используйте abstract для контрактов: Заставьте подклассы реализовать ключевые методы.
Конструкторы в abstract: Полезны для общих init.
Комбинируйте с полиморфизмом: Ссылки на abstract класс для коллекций подклассов.
Избегайте: Не делайте все abstract — используйте concrete для общего.
Ресурсы: Oracle Tutorials on Abstract Classes.



#Java #для_новичков #beginner #Abstract
👍4
Что выведет код?

public class Task040925 {
public static void main(String[] args) {
String s1 = "Java";
String s2 = new String("Java");
String s3 = s2.intern();
String s4 = new StringBuilder("Ja").append("va").toString();
String s5 = s4.intern();

System.out.println((s1 == s3) + " " + (s1 == s5) + " " + (s4 == s5));
}
}


#Tasks
👍2
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Вопрос с собеседований

Ч
то такое string concatenation оптимизация в Java? 🤓

Ответ:

Компилятор Java оптимизирует конкатенацию строк с помощью StringBuilder под капотом для эффективности.

Пример:
String s = "a" + "b" + "c"; // Компилятор преобразует в StringBuilder.append()

Для циклов лучше явно использовать StringBuilder для избежания создания множества временных объектов.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🗓 История IT-технологий сегодня — 5 сентября


ℹ️ Кто родился в этот день

Роберт Хит Деннард (5 сентября 1932 г. – 23 апреля 2024 г.) — изобретатель DRAM и автор принципа «масштабирование Деннарда», фундамент для роста вычислительной техники.

Стеван Манев Додунеков (болг. Стефан Манев Додунеков; 5 сентября 1945, Килифарево — 5 августа 2012, София) — болгарский математик/информатик, работы по кодированию и криптографии, руководил ИМИ БАН.


🌐 Знаковые события

1977 — Запущена автоматическая межпланетная станция «Вояджер-1».

1990 — Компания IBM впервые анонсировала последовательный оптический интерфейс ESCON.


#Biography #Birth_Date #Events #05Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Сети, Volume, ENV и логи в Docker

Основы: архитектурные компоненты Docker

Что такое Docker-сеть? Концепция изоляции и коммуникации
Docker-сеть — это виртуальная изолированная среда, построенная на механизмах ядра Linux (network namespaces, iptables, виртуальные Ethernet-пары), обеспечивающая коммуникацию между контейнерами и внешним миром.

Каждая сеть предоставляет контейнерам собственное сетевое пространство, включающее:
- Интерфейсы (loopback, Ethernet),
- Таблицы маршрутизации,
- Правила firewall (iptables/nftables).


Без сетей контейнеры не смогли бы взаимодействовать друг с другом или с хостом. Изоляция предотвращает конфликты портов (например, два контейнера с веб-сервером на порту 80) и обеспечивает безопасность через segmentation.


Docker Networking: bridge, host, overlay

1. Bridge (по умолчанию)
Bridge-сеть — изолированная сеть на уровне хоста, где контейнеры общаются через виртуальный коммутатор (bridge). Это аналог домашнего роутера: контейнеры получают внутренние IP-адреса, а трафик к внешнему миру проходит через NAT.

Как это работает:
- Docker Daemon создает bridge-интерфейс (обычно docker0) на хосте. Это виртуальный коммутатор уровня L2.

- Для каждого контейнера генерируется virtual Ethernet pair (veth):
- Один конец подключается к docker0 (на хосте),
- Второй — к network namespace контейнера (изолированное сетевое пространство).

- Network namespace — механизм ядра Linux, изолирующий сетевые ресурсы (интерфейсы, таблицы маршрутизации). Контейнер «видит» только свои интерфейсы, не мешая другим процессам.

- Трафик между контейнерами фильтруется через iptables:
- Правила NAT (POSTROUTING) маскируют исходящие пакеты (SNAT),
- Правила FORWARD разрешают коммуникацию внутри сети.


Пример:
docker run -d --name web nginx

- Контейнер web получает IP вида 172.17.0.2 в сети docker0.
- При запросе curl http://web с другого контейнера в той же сети:
1. DNS-резолвер Docker преобразует web в
172.17.0.2,
2. Пакет передается через veth-пару в docker0,
3. Доставляется в контейнер web без участия хоста.


Нюансы:
- Проброс портов (-p 8080:80) добавляет правило в цепочку DOCKER iptables, перенаправляющее трафик с хоста в контейнер.
- Для связи между контейнерами в разных bridge-сетях требуется user-defined bridge (создается через docker network create).



2. Host-сеть
Контейнер использует сетевой стек хоста напрямую, без изоляции. Это как запуск процесса на хосте, но с изоляцией процессов и файловой системы.

Как это работает:
- Контейнер не получает отдельный network namespace. Все сокеты хоста доступны внутри контейнера.
- Порты, занятые контейнером (например, 80), недоступны другим процессам хоста.


Пример:
docker run --network host -d nginx

- Nginx слушает порт 80 на хосте напрямую.
- Нет накладных расходов на NAT, но конфликты портов неизбежны при запуске нескольких сервисов.


Когда использовать:
- Для высокопроизводительных сетевых утилит (tcpdump, haproxy),
- В embedded-системах, где изоляция не требуется.



3. Overlay-сеть
Сеть для multi-host оркестрации (требует Docker Swarm или Kubernetes). Позволяет контейнерам на разных серверах общаться как в одной локальной сети.

Как это работает:
- Использует VXLAN (Virtual Extensible LAN) для туннелирования трафика между узлами.
- VXLAN — технология инкапсуляции L2-кадров в UDP-пакеты. Каждый пакет получает заголовок с VXLAN Network Identifier (VNI), идентифицирующим сеть.
- Распределенное хранилище (Consul/Etcd) синхронизирует состояние сети между нодами.

- Encap/Decap:
- При отправке пакета с узла A на узел B:
1. Данные инкапсулируются в UDP-дейтаграмму с VNI,
2. Передаются по физической сети,
3. На узле B извлекаются из туннеля.


Пример:
docker network create -d overlay my_overlay

- Требует открытия портов:
- 7946 (TCP/UDP) — для обнаружения узлов,
- 4789 (UDP) — для VXLAN-трафика.


Нюансы:
- Задержки выше, чем в bridge, из-за инкапсуляции.
- В Kubernetes вместо overlay используется CNI (Container Network Interface) с плагинами (Calico, Flannel).


#Java #middle #Docker #Bridge #Host #Overlay
👍3🔥1
Volumes и bind-mounts: управление данными

Volume — это механизм хранения данных, независимый от жизненного цикла контейнера. В отличие от данных внутри контейнера (которые удаляются при его остановке), volume сохраняет информацию даже после удаления контейнера. Это достигается через выделение отдельного места на диске хоста с управлением через Docker Engine.

Зачем это нужно?
- Персистентность данных (БД, конфиги),
- Обмен данными между контейнерами,
- Изоляция от изменений на хосте.



1. Named Volumes
Именованные тома, управляемые Docker. Хранятся в /var/lib/docker/volumes/.

Как это работает:
- Docker создает том в /var/lib/docker/volumes/db_data/_data.
- При монтировании в контейнер используется bind mount с флагом rprivate (изоляция от изменений на хосте).
- OverlayFS: Для образов с несколькими слоями volume монтируется как верхний writable-слой.


Пример:
volumes:
db_data:
services:
db:
volumes:
- db_data:/var/lib/postgresql/data

- При старте контейнера:
1. Docker проверяет наличие тома db_data,
2. Если том новый — инициализирует его пустой директорией,
3. Монтирует в контейнер через mount-системный вызов.


Нюансы:
- Владелец тома — пользователь внутри контейнера (например, postgres в образе PostgreSQL).
- При удалении контейнера том не удаляется — требуется docker volume prune.



2. Bind Mounts
Прямое сопоставление директории хоста и контейнера.

Как это работает:
- Ядро Linux связывает inode хоста (./logs) и контейнера (/app/logs) через mount namespace.
- Все операции записи в /app/logs отражаются на хосте в ./logs.


Пример:
services:
app:
volumes:
- ./logs:/app/logs

- inode — уникальный идентификатор файла в файловой системе. При bind mount inode хоста и контейнера совпадают.

Критические ограничения:
- Производительность ниже, чем у named volumes (отсутствие кэширования overlayfs),
- Риск повреждения данных при одновременной записи из хоста и контейнера.


#Java #middle #Docker #Volumes
👍3🔥1
Переменные окружения (ENV, .env)

Это динамические пары ключ=значение, доступные процессу во время выполнения. В Linux они хранятся в памяти процесса как null-terminated строки (например, PATH=/usr/bin).

Как это работает в Docker:
- При старте контейнера Docker Daemon добавляет переменные в process namespace через execve-системный вызов.
- Значения копируются в память процесса (PID 1 контейнера) при его создании.


Пример:
environment:
DB_URL: jdbc:postgresql://db:5432/mydb


- Внутри контейнера переменная доступна через:

  cat /proc/1/environ | tr '\0' '\n'  # PID 1 — процесс Java

Нюансы безопасности:
- Переменные видны в docker inspect и через /proc/<pid>/environ,
- Никогда не передавайте секреты через environment — используйте Docker Secrets или Vault.



Продвинутые сценарии

Секреты: от Docker Secrets до Vault

Что такое секреты в контексте Docker?
Это конфиденциальные данные (пароли, токены), требующие защищенного хранения и передачи. В отличие от переменных окружения, секреты шифруются и изолируются от неавторизованного доступа.

Docker Secrets (Swarm mode)

Как это работает:
- Секреты монтируются как файлы в /run/secrets/ через tmpfs (RAM-диск).
- При монтировании устанавливаются права 000 — доступ только через docker exec.
- Шифрование: секреты передаются по TLS между менеджерами Swarm и хранятся в Raft-логе шифрованными.


Пример:
echo "my_password" | docker secret create db_password -

- Raft-лог: Алгоритм консенсуса для распределенных систем. В Swarm используется для синхронизации состояния секретов.

Недостатки:
- Не подходит для Compose (требует Swarm),
- Нет ротации — при обновлении секрета нужно пересоздавать сервис.



Конфигурация логирования: драйверы и их особенности

Что такое драйвер логирования?

Это модуль, определяющий, как Docker перехватывает и обрабатывает stdout/stderr контейнера. По умолчанию используется json-file, но можно подключить сторонние системы (Fluentd, Syslog).

Как это работает:
- Docker Daemon перехватывает потоки stdout/stderr через pipe (канал межпроцессного взаимодействия).
- Данные передаются в драйвер, который форматирует и отправляет их в указанное место.


Пример для gelf:
logging:
driver: gelf
options:
gelf-address: "udp://graylog:12201"


- GELF (Graylog Extended Log Format) — бинарный формат для структурированных логов.

Поддерживает поля:
  {"version": "1.1", "host": "app", "short_message": "Error", "level": 3}

Нюансы:
- UDP не гарантирует доставку — возможна потеря логов при перегрузке,
- Для надежности используйте tcp вместо udp, но снизится производительность.


#Java #middle #Docker #env
👍4🔥1
Тонкая настройка JVM через переменные окружения

Control Groups (cgroups) — механизм ядра Linux для ограничения, учета и изоляции использования ресурсов (CPU, память, дисковый I/O) группой процессов. Docker использует cgroups для ограничения ресурсов контейнера.

Как это влияет на JVM?
- Если в контейнере установлен лимит памяти (--memory=512m), JVM не видит его по умолчанию и пытается выделить память, превышающую лимит.

Решение:
  environment:
JAVA_TOOL_OPTIONS: "-XX:MaxRAMPercentage=75.0"

- -XX:MaxRAMPercentage указывает JVM использовать 75% от лимита cgroups, а не от общей памяти хоста.


Как это работает:
- JVM читает лимиты из /sys/fs/cgroup/memory/memory.limit_in_bytes (путь внутри cgroup контейнера).
- При старте выделяет heap через mmap с учетом лимита.


Критические ошибки:
- Если -Xmx превышает лимит cgroups, JVM упадет с Native memory allocation (mmap) failed.
- Для контейнеров никогда не используйте `-Xmx` без учета cgroups.



Пример: Java-сервис с ENV и логами в volume

docker-compose.yml
version: '3.8'
services:
app:
build: ./app
environment:
DB_URL: jdbc:postgresql://db:5432/mydb
DB_PASSWORD: ${DB_PASSWORD}
volumes:
- app_logs:/app/logs
logging:
driver: json-file
options:
max-size: "50m"
networks:
- app_net

db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
networks:
- app_net

volumes:
app_logs:
driver: local
pg_data:

networks:
app_net:
driver: bridge


Концептуальное объяснение
:
1. Сеть app_net:
- Создает bridge-сеть через docker network create.
- Контейнеры app и db получают IP в подсети
172.18.0.0/16 и могут общаться по именам (db:5432).

2. Том pg_data:
- Хранится в /var/lib/docker/volumes/pg_data/_data.
- При старте PostgreSQL инициализирует данные в этом каталоге.


3. Логирование:
- Драйвер json-file пишет логи в /var/lib/docker/containers/<id>/<id>-json.log.
- При достижении 50m файл ротируется, сохраняя 3 архива.


Код Java-приложения:
public class Main {
public static void main(String[] args) {
String dbUrl = System.getenv("DB_URL"); // Чтение из process namespace
try (Connection conn = DriverManager.getConnection(
dbUrl, "user", System.getenv("DB_PASSWORD"))) {
// Запись в файловый лог
try (FileWriter fw = new FileWriter("/app/logs/application.log", true)) {
fw.write("DB connection established\n");
}
}
}
}


Почему это работает
:
- Переменные DB_URL и DB_PASSWORD передаются через process namespace, что безопаснее hardcode.
- Том app_logs изолирует логи от жизненного цикла контейнера — данные сохраняются после docker-compose down.
- JVM учитывает лимиты cgroups благодаря -XX:MaxRAMPercentage.



Best practices

1. Сети:
- Bridge — для локальной разработки,
- Overlay/CNI — для продакшена,
- Host — только для специфических задач.


2. Volumes:
- Named volumes — для БД и персистентных данных,
- Bind mounts — только для разработки (hot-reload).


3. Секреты:
- Всегда используйте Vault или Kubernetes Secrets в продакшене,
- Избегайте .env для секретов — он не шифруется.


4. Логирование:
- Настройте централизованное логирование (Fluentd + Elasticsearch),
- Используйте gelf или fluentd вместо json-file в продакшене.


5. JVM:
- Всегда ограничивайте память через -XX:MaxRAMPercentage,
- Проверяйте лимиты cgroups через cat /sys/fs/cgroup/memory/memory.limit_in_bytes.



#Java #middle #Docker #best
👍3🔥1