Практично Groovy Підмішайте трохи Groovy у програмі Java
Використовуйте простоту Groovy, вбудовуючи прості та легкі у написанні сценарії
Серія контенту:
Цей контент є частиною # із серії # статей: Практично Groovy
Цей контент є частиною серії: Практично Groovy
Слідкуйте за виходом нових статей цієї серії.
Якщо ви вже читали статті цієї серії, ви могли побачити, що існує безліч цікавих способів використання Groovy, і однією з основних переваг Groovy є продуктивність роботи програміста. Код Groovy найчастіше простіший і легкий у написанні, ніж код Java, що робить його ще більш цінним доповненням до вашого інструментарію розробки. З іншого боку, як я вже неодноразово наголошував у рамках серії, Groovy не є заміною мови Java і не призначений для цього. Отже, питання полягає в тому, чи можете ви впровадити Groovy у практику програмування Java, і чи корисно це, а якщо корисно – коли?
Цього місяця я спробую відповісти на це запитання. Я почну з того, що ви вже знаєте - як сценарії Groovy компілюються в Java-сумісні файли класу, після чого заглиблюся в докладний опис того, як засоби компіляції Groovy (groovyc) роблять це можливим. Розуміння того, як працює Groovy - це перший крок до використання його в коді Java
Зверніть увагу, що деякі методики програмування, продемонстровані в цій статті, лежать в основі інфраструктури Groovlets та GroovyTestCase Groovy, які я розглядав минулого місяця.
Про цю серію посібників
Щоб використовувати будь-який інструмент у практиці розробки, необхідно знати, як ним користуватися і коли його краще відкласти убік. Мови сценаріїв можуть бути надзвичайно корисним помічником, алетільки якщо застосовувати їх правильно та у відповідних ситуаціях. У зв'язку з цим у серії статей практично Groovy ми розглядаємо практичні застосування Groovy і показуємо, коли і як його можна успішно використовувати.
Чи правда, що шлюби укладаються на небесах?
В одній із попередніх статей цієї серії, коли я показував, як проводити модульне тестування звичайних програм Java за допомогою Groovy, ви могли помітити одну особливість: компілював сценарії Groovy. Справді, я скомпілював модульні тести у звичайні файли .class Java і запустив їх у процесі компонування Maven.
Компіляція такого типу виконується шляхом виклику команди groovyc, яка компілює сценарії Groovy у старі добрі файли .class, сумісні з Java. Наприклад, якщо у сценарії оголошено три класи, виклик groovyc призведе до створення трьох файлів .class. Самі файли будуть відповідати стандартним правилам Java, згідно з якими назва файлу .class збігається з назвою класу.
Для прикладу давайте подивимося на листинг 1, який створює простий сценарій, який оголошує кілька класів. Ви можете побачити, що виводить команда groovyc:
Лістинг 1. Декларація та компіляція класу в Groovy
У лістингу 1 я оголосив три класи - Person, Address та ContactNumber. Наведений нижче код створює об'єкти щойно певних типів і викликає метод toString() . Поки що все досить просто, але давайте подивимося, що вийшло в результаті роботи groovyc, наведеному в лістингу 2:
Лістинг 2. Класи, створені командою groovyc
Ого, п'ять файлів. Існування файлів Person , Address та ContactNumber зрозуміле, але навіщо потрібно ще два?
З'ясовується, що Person$_toString_closure1.class з'явився внаслідок замикання в методіtoString() класу Person. Фактично він є внутрішнім класом Person. А звідки з'явився файл BusinessObjects.class?
Кодування навпаки
Декомпіляція цих класів може бути дуже цікавою. Виконані файли .java будуть значно більше за розміром, завдяки природі прихованого коду Groovy; однак, ви, ймовірно, помітили різницю між класами, оголошеними у сценарії Groovy (наприклад, Person) і кодом поза класами (наприклад, код BusinessObjects.class). Класи, визначені в Groovy, завершуються реалізацією GroovyObject, а код, розташований за межами класу, входить до класу, що розширює Script.
Наприклад, якщо ви вивчите файл .java, що вийшов з BusinessObjects.class, ви побачите, що в ньому визначається методи main() та run(). Очевидно, метод run() містить код, який я написав для створення нових екземплярів об'єктів, а метод main() викликає метод run() .
Суть цього висновку полягає в тому, що чим краще ви розумієте Groovy, тим простіше вбудувати його в програми Java. "І навіщо мені це потрібно?" - спитаєте ви? Отже, скажімо, ви розробили щось особливе в Groovy; правда, було б непогано вбудувати це також у вашу програму на Java?
Просто заради наочності, я спочатку спробую створити в Groovy щось корисне, після чого я розгляну різні способи його впровадження у звичайну програму Java.
І знову музика у Groovy
Я люблю музику. Насправді, моя колекція компакт-дисків змагається за розмірами з бібліотекою книг по комп'ютерах. Протягом багатьох років я переписував музику на різні комп'ютери і, по ходу справи, заплутав свою колекцію MP3 до межі – сьогодні я маю безліч каталогів, що містять найрізноманітнішу музику.
Нещодавно я зробив перші кроки до наведенняпорядку у моїй музичній колекції. Я написав невеликий сценарій Groovy, який циклічно проходив по колекції MP3-файлів, що містяться в папці, і надавав мені докладну інформацію про кожен файл - виконавець, назву альбому і т.п. Цей сценарій показаний у лістингу 3:
Лістинг 3. Дуже корисний сценарій Groovy
Як ви можете бачити, сценарій дуже простий, особливо враховуючи його корисність у ситуації, подібній до моєї. Все, що мені потрібно робити, це передавати назву певної директорії, і я отримаю потрібну інформацію (ім'я виконавця, назву пісні та альбому) для кожного файлу MP3 в цій директорії.
Тепер давайте подивимося, що мені потрібно зробити, щоб впровадити цей чудовий сценарій у звичайну програму Java, яка може організовувати музику за допомогою бази даних або навіть програвати MP3.
Файли класів та файли класів
Насправді groovyc створить п'ять файлів .class. Це співвідноситься з тим фактом, що Songs.groovy містить три замикання, два в методі getSongsForDirectory() і один у тілі сценарію, коли я формував цикл по колекції Song і викликав println .
Тепер у мене є два варіанти впровадження щойно скомпільованого коду Groovy у код Java: Я можу запускати код через метод main() , реалізований у файлі класу Songs.class (оскільки він розширює Script ), також я можу включати Song.class у шлях класів та використовувати його так само, як і будь-які інші об'єкти в коді Java.
Будемо простіше
Виклик файлу Songs.class за допомогою команди java гранично простий, якщо ви не забуваєте увімкнути залежності Groovy та всі можливі залежності сценарію Groovy. Найпростіший спосіб включення необхідних класів Groovy полягає у включенні у шлях класів файлів jar "все в одному", що вбудовуються в Groovy.У моєму випадку це файл groovy-all-1.0-beta-10.jar. Для запуску Songs.class мені також потрібно не забути включити бібліотеку MP3, що використовується мною (jid3lib-0.5.jar>), і оскільки я використовую AntBuilder , мені також потрібно включити в шлях класу Ant . У лістингу 4 все зводиться разом:
Лістинг 4. Groovy через командний рядок Java
Впровадження Groovy у код Java
Незважаючи на те, що рішення, що працює в командному рядку, легке та зручне, воно не є універсальним. Якби мені було цікаво перейти на більш високий рівень складності, я міг би імпортувати мою MP3 утиліту безпосередньо в програму Java. У цьому випадку я міг би імпортувати Song.class і використовувати його так само, як і будь-який інший клас мови Java. Проблеми шляхом класів будуть такими ж, як і раніше: мені потрібно не забути включити файл архіву uber-Groovy , Ant , і файл jid3lib-0.5.jar. У лістингу 5 ви можете побачити, як я імпортував MP3-утиліту Groovy як приклад Java:
Лістинг 5. Вбудований код Groovy
Завантажувачі класів Groovy
Ви думаєте, що вже все довідалися? Виявляється, є ще кілька способів потішитися з Groovy Java. Крім вбудовування сценаріїв Groovy у програми Java за допомогою прямої компіляції, у мене також є кілька варіантів вбудовування безпосередньо сценаріїв.
Наприклад, я можу за допомогою GroovyClassLoader Groovy здійснити динамічне завантаження сценарію Groovy та його виконання, як показано в лістингу 6:
Лістинг 6. Groovy >
Класи Meta
Якщо ви один із тих психов, кому подобаються відображення і ті чудові речі, які можна з ними зробити, класи Meta Groovy зведуть вас з розуму. Так само, як і у разі відображення, використовуючи ці класи, ви можете дізнатися багато нового про GroovyObject, наприклад, про йогометоди, і ви можете дійсно створювати нові алгоритми і виконувати їх. Це, до речі, і є серце Groovy – і лише уявіть, як воно працює, коли ви запускаєте сценарії!
Зверніть увагу, що за замовчуванням завантажувач класу завантажує клас, що відповідає назві сценарію - в даному випадку Songs.class, а не Song.class>. Оскільки ми з вами знаємо, що Songs.class розширює клас Script Groovy, зрозуміло, що мою наступну дію буде виконання методу run() .
Ви, напевно, пам'ятаєте, що мій сценарій Groovy також залежав від аргументів, які передаються під час роботи програми. Тому мені потрібно налаштувати змінну args відповідним чином, тому що в даному випадку я першим елементом встановив назву директорії.
Більше динаміки
Альтернатива використанню компільованих класів та динамічному завантаженню GroovyObject за допомогою завантажувачів класів полягає у використанні GroovyScriptEngine та GroovyShell для динамічного виконання сценаріїв Groovy.
Впровадження об'єкта GroovyShell у звичайні класи Java дозволяє динамічно виконувати сценарії Groovy так само, як це робить завантажувач класу. Крім того, це дає кілька можливостей запуску сценаріїв. У лістингу 7 показано, як GroovyShell впроваджений у стандартний клас Java:
Лістинг 7. Використання GroovyShell
Як можна побачити, сценарій Groovy запускається дуже просто. Я просто створюю екземпляр GroovyShell, передаю назву сценарію і викликаю метод run().
Але це не все. Якщо хочете, ви можете запросити екземпляр GroovyShell для типу Script сценарію. Використовуючи тип Script , ви можете передавати об'єкт Binding , що містить всі необхідні параметри, і викликати метод run() , як показано у лістингу 8.
Лістинг 8. Забавляємось зGroovyShell
Механізм сценаріїв Groovy
Об'єкт GroovyScriptEngine працює так само, як GroovyShell для сценаріїв, що динамічно запускаються. Відмінність GroovyScriptEngine полягає в тому, що при створенні екземпляра ви можете вказати йому кілька директорій, після чого ви можете будь-коли викликати кілька сценаріїв, як показано в лістингу 9:
Лістинг 9. GroovyScriptEngine у дії
У лістингу 9 я передаю масив, що містить потрібний мені шлях, створеному екземпляру GroovyScriptEngine, створюю старий знайомий об'єкт Binding і виконую також знайомий сценарій Songs.groovy. Просто заради гри, я запускаю сценарій BusinessObjects.groovy , який ви, можливо, пам'ятаєте з початку цього обговорення.
Середовище сценаріїв Bean
Останнім, але дуже важливим способом є середовище сценаріїв Bean Scripting Framework (BSF) проекту Jakarta. Мета BSF - запропонувати загальний API для впровадження будь-якої мови сценаріїв, у тому числі Groovy, у звичайний додаток Java. Цей стандартний, хоча, можливо, надмірно загальний підхід дозволяє вам впроваджувати сценарії Groovy без жодних зусиль.
Пам'ятаєте наведений вище сценарій BusinessObjects? У лістингу 10 показано, як просто BSF дозволяє вам вбудувати його у звичайну програму Java:
Лістинг 10. BSF у роботі
Висновок
Якщо що і ясно з цієї статті, то це те, що Groovy відкриває безліч варіантів повторного використання в Java коді. У всіх випадках, від компіляції сценаріїв Groovy до звичайних старих файлів .class Java до динамічного завантаження та запуску сценаріїв, головне, на що потрібно звертати увагу - це гнучкість і можливість спільної роботи. Компіляція сценаріїв Groovy у звичайні файли .class - це найпростіший спосіб використання функцій, які ви вбудовуєте, тоді якдинамічне завантаження сценаріїв спрощує додавання та зміну алгоритмів роботи без витрат часу на компіляцію. (Звичайно, цей варіант працює тільки в тому випадку, якщо інтерфейс не змінився.)
Вбудовування мов сценаріїв у звичайний код Java не є повсякденним явищем, але іноді такі можливості надаються. У наведених прикладах я вбудовував просту утиліту пошуку за каталогами в додаток Java, який може бути MP3-плеєром або іншою утилітою для роботи з MP3. Незважаючи на те, що я можу переписати мою утиліту пошуку файлів MP3 в код Java, мені не потрібно цього робити: Groovy чудово сумісний з мовою Java, і, крім того, я чудово побавився, розбираючись з усіма можливостями!