Почти Groovy Смесете малко Groovy във вашите Java приложения
Възползвайте се от простотата на Groovy чрез вграждане на скриптове, които са прости и лесни за писане
Серия съдържание:
Това съдържание е част # от поредица # статии: Practical Groovy
Това съдържание е част от поредицата: Practically Groovy
Очаквайте нови статии от тази серия.
Ако вече сте чели статиите в тази поредица, може би сте видели, че има много интересни начини за използване на Groovy и едно от основните предимства на Groovy е производителността на програмиста. Groovy кодът често е по-прост и лесен за писане от Java кода, което го прави още по-ценно допълнение към вашия инструментариум за разработка. От друга страна, както посочвах много пъти в поредицата, Groovy не е и не е предназначен да бъде заместител на езика Java. Така че въпросът е, можете ли да включите Groovy във вашата практика за програмиране на Java и полезно ли е, и ако да, кога?
Този месец ще се опитам да отговоря на този въпрос. Ще започна с това, което вече знаете – как скриптовете на Groovy се компилират в Java-съвместими клас файлове и след това ще се потопя в подробно описание на това как инструментите за компилиране на Groovy (groovyc) правят това възможно. Разбирането как работи Groovy е първата стъпка към използването му в Java код.
Имайте предвид, че някои от техниките за програмиране, демонстрирани в тази статия, са в основата на Groovlets и GroovyTestCase Groovy рамки, които прегледах миналия месец.
Относно тази серия от ръководства
За да използвате който и да е инструмент в практиката за разработка, трябва да знаете как да го използвате и кога е по-добре да го оставите настрана. Скриптовите езици могат да бъдат изключително полезни, носамо ако се прилагат правилно и в подходящи ситуации. За тази цел в поредицата Practical Groovy разглеждаме практически приложения на Groovy и показваме кога и как може да се използва успешно.
Вярно ли е, че браковете се сключват на небето?
В по-ранна статия от тази поредица, когато ви показах как да тествате модулно обикновени Java програми с Groovy, може би сте забелязали едно нещо: компилирах Groovy скриптове. Наистина, компилирах модулните тестове в обикновени Java .class файлове и ги пуснах в процеса на изграждане на Maven.
Този тип компилация се извършва чрез извикване на командата groovyc, която компилира Groovy скриптове в добрите стари Java съвместими .class файлове. Например, ако скрипт декларира три класа, извикването на groovyc ще генерира три .class файла. Самите файлове ще следват стандартните правила на Java, че името на файла .class е същото като името на класа.
Например, нека да разгледаме листинг 1, който създава прост скрипт, който декларира няколко класа. Можете да видите какво извежда командата groovyc:
Листинг 1. Деклариране и компилиране на клас в Groovy
В листинг 1 декларирах три класа – Person, Address и ContactNumber. Кодът по-долу създава обекти от типовете, които току-що дефинирахме, и извиква метода toString(). Дотук е доста просто, но нека да видим как изглежда изходът на groovyc в списък 2:
Листинг 2. Класове, генерирани от groovyc
Леле, пет .class файла! Съществуването на файловете 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 в classpath. Списък 4 събира всичко заедно:
Листинг 4. Groovy чрез командния ред на Java
Вграждане на Groovy в Java код
Въпреки че решението на командния ред е леко и удобно, то не е универсално. Ако се интересувах от по-високо ниво на сложност, бих могъл да импортирам моята MP3 програма директно в Java програма. В този случай мога да импортирам Song.class и да го използвам точно като всеки друг клас на езика Java. Проблемите с classpath ще бъдат същите като преди: трябва да запомня да включа архивния файл uber-Groovy, Ant и файла jid3lib-0.5.jar. В листинг 5 можете да видите как импортирах помощната програма Groovy MP3 в примерния Java клас:
Листинг 5. Вграден Groovy код
Товарачи от клас Groovy
Мислите ли, че вече знаете всичко? Оказва се, че има няколко други начина да си поиграете с Groovy в Java. В допълнение към вграждането на Groovy скриптове в Java програми чрез директна компилация, имам и няколко опции за директно вграждане на скриптове.
Например, мога динамично да заредя Groovy скрипт и неговото изпълнение с помощта на GroovyClassLoader Groovy, както е показано в списък 6:
Списък 6. Groovy >
Мета класове
Ако сте един от онези луди, които обичат отраженията и страхотните неща, които можете да правите с тях, класовете Meta Groovy ще ви впечатлят. Точно както при отраженията, с помощта на тези класове можете да научите много за GroovyObject, например за неговияметоди и всъщност можете да създавате нови алгоритми и да ги изпълнявате. Това, между другото, е сърцето на Groovy -- и само си представете как работи, когато изпълнявате скриптове!
Имайте предвид, че по подразбиране програмата за зареждане на класове зарежда класа, който съответства на името на скрипта -- в този случай Songs.class, а не Song.class>. Тъй като и двамата знаем, че Songs.class разширява класа Groovy Script, ясно е, че следващата ми стъпка е да изпълня метода 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) на проекта Джакарта. Целта на BSF е да предложи общ API за вграждане на всеки скриптов език, включително Groovy, в обикновено Java приложение. Този стандартен, макар и може би твърде общ, подход ви позволява да внедрявате Groovy скриптове без усилие.
Помните ли скрипта на BusinessObjects по-горе? Списък 10 показва колко лесно BSF ви прави да го вградите в нормална Java програма:
Листинг 10. BSF в действие
Заключение
Ако нещо е ясно от тази статия, това е, че Groovy отваря много опции за повторно използване в Java кода. Във всички случаи, от компилирането на Groovy скриптове в обикновени стари Java .class файлове до динамично зареждане и изпълнение на скриптове, ключовото нещо, което трябва да търсите, е гъвкавостта и сътрудничеството. Компилирането на Groovy скриптове в обикновени .class файлове е най-лесният начин да използвате функциите, които вграждате, докатодинамичното зареждане на скриптове улеснява добавянето и промяната на работните алгоритми без време за компилиране. (Разбира се, тази опция работи само ако интерфейсът не е променен.)
Вграждането на скриптови езици в обикновен код на Java не е ежедневие, но понякога възможността се предоставя. В примерите тук съм вградил проста помощна програма за търсене в директория в Java приложение, което може да бъде MP3 плейър или друга помощна програма за MP3. Въпреки че мога да пренапиша своя MP3 търсач в Java код, не е нужно: Groovy е супер съвместим с езика Java и освен това се забавлявах много, докато изучавах всички функции!