Java agent на службі jvm

Java agent на службі jvm

Напевно багато хто чув або стикалися з таким параметром JVM як -javaagent, побачити цей параметр ви могли використовуючи Jrebel або Plumbr це могло виглядати наприклад так JAVA_OPTS = -javaagent: [path / to /] jrebel.jar або так -javaagent: / path-to /plumbr.jar
Хоча javaagent з'явився ще в версії java 1.5, багато розробників так ніколи і не використали можливості агентів і мають туманне уявлення що це таке.
Що ж це за агент? Навіщо він може нам знадобитися і як написати свій?

Як я написав вище javaagent це один з параметрів JVM, який дозволяє вказати агент який буде запущений з вашим додатком, а точніше він буде запущений ще перед запуском вашого застосування. Сам агент це окремий додаток яке надає доступ до механізму маніпуляції байт-кодом (java.lang.instrument) в runtime. Це якщо коротко. Офіційну документацію можна почитати тут. але вона досить убога. Нічого не зрозуміло? Отже, давайте розбиратися. Найкраще розбиратися на прикладах.

Напишемо елементарний агент

Зверніть увагу, агент обов'язково повинен реалізовувати метод premain з наступною сигнатурою
public static void premain (String args);
або
public static void premain (String args, Instrumentation inst);

Клас агента повинен бути упакований в jar і містити MANIFEST.MF. з обов'язковим атрибутом
PreMain-Class - вказує на клас агента з premain методом. Є й інші атрибути агента, але вони необов'язкові і зараз нам не знадобляться.

Ось так буде виглядати наш manifest.mf.
не забудьте додати новий рядок в кінець файлу

Тепер спакуємо все це в jar

І нарешті клас випробувач

Запускаємо AgentTester з командного рядка

З цього прикладу видно що:

  • метод premain виповнюється ще до виклику методу main основного додатка.
  • агент вказується за допомогою параметра -javaagent: jarpath [= options]

Давайте спробуємо витягти з агента якусь користь


Взагалі механізм агентів призначений для маніпуляції байт-кодом. але скажу відразу модифікувати байт-код в цій статті ми не будемо інакше можна піти далеко-далеко за межі цієї посади. Кому цікаво можна подивитися на javassist так як стандартних засобів для роботи з байт-кодом немає.

Напишемо AgentCounter який буде виводити ім'я завантаженого клас і підраховувати кількість завантажених класів. Так ми зможемо поспостерігати за роботою classloader # 96; a.


Зверніть увагу, тепер я використовую іншу сигнатуру методу premain. В об'єкт instrumentation я передаю ClassTransformer який і виконує всю роботу. ClassTransformer буде спрацьовувати кожного разу при завантаженні класу. Якщо ви хочете використовувати свій ClassTransformer, ви повинні реалізувати інтерфейс java.lang.instrument.ClassFileTransformer і додати свій об'єкт через метод Instrumentation.addTransformer


classfileBuffer - це і є байт-код поточного класу представлений у вигляді масиву байт, для його перевизначення трансформер повинен повернути новий масив байт, в даному прикладі ми не змінюємо вміст класу тому просто повертаємо той же масив.

Пакуємо агент і трансформер в новий jar

Трохи модифікуємо клас тестер

Запускаємо AgentTester c новим агентом
для різних версій java результати можуть відрізнятися

Якщо запустити якусь enterprise додаток з таким агентом, можна отримати досить цікаві результати, наприклад один з проектів після старту видав мені наступне:

Вимірюємо розмір java об'єктів


Розглянемо ще один приклад використання агентів. Напишемо клас який буде повертати розмір java об'єктів і javaagent буде грати ключову роль. Хто як не JVM може знати реальний розмір створеного об'єкта. в інтерфейсі Instrumentation є чудовий метод long getObjectSize (Object objectToSize) який повертає розмір об'єкта. Але як з нашого застосування отримати доступ до агенту? А робити нічого особливого й не доведеться, javaagent автоматично додається в classpath і нам залишається тільки додати в агент поле типу Instrumentation instrumentation та форматувати його в методі premain.


Ми отримуємо доступ до методу AgentMemoryCounter.getSize (obj) з класу додатка.

Результати роботи програми можу виглядати наступним чином

Зверніть увагу що метод getObjectSize () не враховує розмір вкладених об'єктів тобто враховується тільки пам'ять витрачена на посилання на об'єкт.

висновок

Два простих прикладу створення файлового сховища в СУБД
Практично в кожному веб-проект потрібно власне сховище файлів. Призначень у нього безліч. Сьогодні ми розглянемо 2 простих варіанти його створення: перший - з використанням типу даних blob засобами Java, Spring MVC, Hibernate, MySQL і другий - з кластеризацией (розбиттям файлу на шматочки) засобами groovy, grails, hibernate,

Java agent на службі jvm

Java agent на службі jvm

Знайомство з Kotlin та збирання jar за допомогою maven
Це пост замітка про те, як я познайомився з мовою Kotlin, які використовував для цього ресурси, інструменти, і як я зібрав його в jar і запустив в консолі. В общем-то я PHP програміст, трохи Заком з Java. Днями вирішив подивитися Kotlin. Це менш суворо типізований мову від JetBrains до того, що він, по суті, статично типізований. В

Java agent на службі jvm

Підключення шрифтів в своєму проекті
Привіт всім! Кожен, хто розробляв хоч один додаток під андроїд, замислювався про те як би підключити до свого проекту кастомний шрифт. Ось і я задався цим питанням. Є кілька способів. Вод один з них: String custom_font = "fonts / custom_font.ttf"; Typeface CF = Typeface.createFromAsset (getAssets (), custom_font);

Java agent на службі jvm

Визначаємо всі класи, які використовує додаток на Java
Без сумніву кожен, хто в своєму резюме вказує досвід розробки на Java, хоч раз в житті писав рядки public static void main # 40; String # 91; # 93; args # 41; компілював їх і запускав на виконання командою на зразок java HelloWorld. Але чи багато хто знає, що відбувається всередині JVM від моменту виконання цієї команди до того як управління