Статьи

Интеграция Spring & Quartz с пользовательскими аннотациями, способ SPANN

В предыдущем посте мы продемонстрировали, как создавать и настраивать задания Quartz с аннотациями в контейнере Spring . Мы использовали аннотацию на уровне класса, чтобы добавить метаданные в bean-компонент, который реализует работу Quartz; аннотация определяет имя задания, группу и его cron-выражение. Позже большая часть кода посвящена обработке этой аннотации: найдите компоненты, прочитайте аннотацию, создайте JobDetail и CronTrigger , примените их свойства и передайте их планировщику.

Если вы работаете над весенним проектом среднего или большого размера, вы, вероятно, достаточно скоро начнете видеть шаблонную конфигурацию и код, который часто можно реорганизовать, заключив его в аннотации; аннотация @QuartzJob является хорошим примером.

В masetta мы попытались использовать проект Polyforms, чтобы использовать аннотации для реализации методов DAO (которые обычно состоят из некоторого стандартного кода вокруг запроса JPA). Вскоре мы обнаружили, что он не был настолько конфигурируемым и расширяемым, как нам нужно, имел проблемы с обработкой именованных параметров запроса и проблемы порядка инициализации (потому что Polyforms использует аспекты для реализации абстрактных методов). Кроме того, мы использовали пользовательские аннотации и обрабатывали их «вручную», но их становилось слишком много…

То, что мы придумали, это spann . Spann — это расширение с открытым исходным кодом для среды Spring, которая позволяет выполнять расширенную настройку компонентов Spring с использованием аннотаций. Чтобы взглянуть на одну из возможностей spann, я буду опираться на наш предыдущий пост и реализовывать аналогичные функции. Вместо кодирования я буду использовать spann. Как вы увидите, реализация очень короткая.

обзор

В коде используется собственная реализация планирования Quartz от Spring (как объяснено в ссылках на Spring). Метод SpringInvokingJobDetailFactoryBean используется Spring для создания компонента JobDetail, который делегирует выполнение задания методу другого компонента. В качестве триггера я использую весеннюю реализацию CronTrigger .

Для создания и настройки bean- компонентов JobDetail и CronTrigger я буду создавать аннотации на уровне методов, используя аннотацию spanB @BeanConfig .

Код

Пример кода может быть извлечен как проект maven из магистрали spann, используя

svn co http://spann.googlecode.com/svn/trunk/spann-quartz-example

Он включает в себя pom со всеми необходимыми координатами зависимости и функциональный тестовый пример.

1. Создайте аннотацию для настройки MethodInvokingJobDetailFactoryBean

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">package com.masetta.spann.quartzexample.annotations;</span> пакет com.masetta.spann.quartzexample.annotations;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import java.lang.annotation.*;</span> импорт java.lang.annotation. *;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;</span> import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.metadata.common.Artifact;</span> import com.masetta.spann.metadata.common.Artifact;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.spring.base.beanconfig.*;</span> import com.masetta.spann.spring.base.beanconfig. *;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.spring.base.beanconfig.factories.*;</span> import com.masetta.spann.spring.base.beanconfig.factories. *;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Retention(RetentionPolicy.RUNTIME)</span> @Retention (RetentionPolicy.RUNTIME)</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Target({ElementType.METHOD})</span> @Target ({ElementType.METHOD})</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@BeanConfig(</span> @BeanConfig (</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">create=MethodInvokingJobDetailFactoryBean.class,</span> создать = MethodInvokingJobDetailFactoryBean.class,</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">attached=@Attached(role="quartzJob",scope=Artifact.METHOD),</span> присоединенные = @ Attached (роль = "quartzJob", сфера = Artifact.METHOD),</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">explicit=true,</span> Явный = истина,</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">wire={</span> провод = {</span>
  <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@WireMeta(property="targetObject",scope=Artifact.CLASS,factory=BeanReferenceFactory.class),</span> @WireMeta (свойство = "TargetObject", область = Artifact.CLASS, завод = BeanReferenceFactory.class),</span>
  <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@WireMeta(property="targetMethod",scope=Artifact.METHOD,factory=MetadataNameFactory.class)</span> @WireMeta (свойство = "targetMethod", область = Artifact.METHOD, завод = MetadataNameFactory.class)</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">})</span> })</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public @interface QuartzJob {</span> public @interface QuartzJob {</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">String name();</span> Имя строки ();</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">String group();</span> Строковая группа ();</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">boolean concurrent() default true;</span> логическое concurrent () по умолчанию true;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>

Аннотация @BeanConfig создает и настраивает MethodInvokingJobDetailFactoryBean с использованием атрибутов аннотации QuartzJob ( имя , группа и одновременность ).

Сконфигурированный компонент «присоединяется» к аннотированному методу с ролью « quartzJob ». Это будет использовано позже для внедрения компонента JobDetail в триггер. «Присоединение» — это внутренняя концепция spann. Он позволяет ссылаться на bean-компоненты путем указания артефакта (например, класса или метода) и семантической роли (здесь «quartzJob») вместо имени. Это позволяет составлять аннотации , самую мощную функцию spann, которая также демонстрируется здесь.

Атрибут wire устанавливает свойства targetObject и targetMethod со значениями, заполненными из метаданных текущего артефакта (в данном случае MethodMetadata ), ScanContext и Annotation с использованием заданных фабрик.

2. Создайте cron триггер Аннотация

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">package com.masetta.spann.quartzexample.annotations;</span> пакет com.masetta.spann.quartzexample.annotations;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import java.lang.annotation.*;</span> импорт java.lang.annotation. *;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import org.springframework.scheduling.quartz.CronTriggerBean;</span> import org.springframework.scheduling.quartz.CronTriggerBean;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.metadata.common.Artifact;</span> import com.masetta.spann.metadata.common.Artifact;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.spring.base.beanconfig.*;</span> import com.masetta.spann.spring.base.beanconfig. *;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Retention(RetentionPolicy.RUNTIME)</span> @Retention (RetentionPolicy.RUNTIME)</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Target(ElementType.METHOD)</span> @Target (ElementType.METHOD)</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@BeanConfig(</span> @BeanConfig (</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">create=CronTriggerBean.class,</span> создать = CronTriggerBean.class,</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">attached=@Attached(role="quartzTrigger",scope=Artifact.METHOD),</span> прилагается = @ Attached (роль = "quartzTrigger", область = Artifact.METHOD),</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">explicit=true,</span> Явный = истина,</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">references=@SpannReference(property="jobDetail",role="quartzJob", scope=Artifact.METHOD)</span> reference = @ SpannReference (property = "jobDetail", role = "quartzJob", scope = Artifact.METHOD)</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">)</span> )</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public @interface Cron {</span> public @interface Cron {</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">String cronExpression();</span> Строка cronExpression ();</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">String timeZone() default "";</span> String timeZone () default "";</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">String misfireInstructionName() default "";</span> Строка misfireInstructionName () по умолчанию "";</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">String[] triggerListenerNames() default {};</span> String [] triggerListenerNames () default {};</span>
  
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>

Я снова использую аннотацию @BeanConfig , на этот раз создавая и конфигурируя CronTriggerBean .

Явный атрибут указывает, как обрабатывать значения атрибута аннотации по умолчанию. Когда явное значение true, значения атрибутов по умолчанию игнорируются. Например, свойства timeZone , misfireInstructionName и triggerListenerNames элемента CronTriggerBean будут установлены, только если установлено соответствующее значение атрибута аннотации; значение по умолчанию будет игнорироваться.

Используя атрибут links, для свойства jobDetail устанавливается bean-компонент, созданный на шаге 1: spann будет искать bean-компонент, прикрепленный к аннотированному методу с рольюquartzJob ‘.

Обратите внимание, что типом атрибута аннотации timeZone является String , а типом свойства timeZone объекта CronTriggerBean является TimeZone . Spring обрабатывает значение напрямую, прозрачно преобразуя его в TimeZone с помощью средства SpringE PropertyEditor . Вы даже можете использовать синтаксис $ {…} Spring для подстановки выражений.

Зарегистрированный код содержит третью аннотацию для создания интервального триггера, который будет использован позже в этом примере.

3. Настройка spann и Spring’s SchedulerFactoryBean

Наше applicationContext.xml очень короткое:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left"><beans xmlns="http://www.springframework.org/schema/beans"</span> <beans xmlns = "http://www.springframework.org/schema/beans"</span>
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span> XMLNS: XSI = "http://www.w3.org/2001/XMLSchema-instance"</span>
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">xmlns:context="http://www.springframework.org/schema/context"</span> XMLNS: контекст = "http://www.springframework.org/schema/context"</span>
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">xmlns:spann="http://os.masetta.com/spann/schema/spann-1.0"</span> XMLNS: Спан = "http://os.masetta.com/spann/schema/spann-1.0"</span>
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">xsi:schemaLocation="</span> XSI: SchemaLocation =»</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd</span> http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd</span> http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">http://os.masetta.com/spann/schema/spann-1.0 http://os.masetta.com/spann/schema/spann-1.0.xsd"></span> http://os.masetta.com/spann/schema/spann-1.0 http://os.masetta.com/spann/schema/spann-1.0.xsd "></span>
 
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left"><context:component-scan base-package="com.masetta.spann.quartzexample"/></span> <context: component-scan base-package = "com.masetta.spann.quartzexample" /></span>
     
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left"><spann:scan base-package="com.masetta.spann.quartzexample"/></span> <spann: scan base-package = "com.masetta.spann.quartzexample" /></span>
     
    <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left"><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire=”byType”/></span> <bean class = "org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire = ”byType” /></span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left"></beans></span> </ Бобы></span>

Если вы знаете Spring, здесь не должно быть никакого волшебства: я настраиваю сканирование компонентов Spring, сканирование spann и SchedulerFactoryBean , как описано в справочнике spring, только здесь я позволяю Spring автоматически связывать все триггерные бины с соответствующим свойством, следовательно, autowire = ‘byType’ .

4. Использование аннотаций

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">package com.masetta.spann.quartzexample.test;</span> пакет com.masetta.spann.quartzexample.test;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import java.util.concurrent.atomic.AtomicInteger;</span> import java.util.concurrent.atomic.AtomicInteger;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import org.springframework.stereotype.Component;</span> import org.springframework.stereotype.Component;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.quartzexample.annotations.*;</span> import com.masetta.spann.quartzexample.annotations. *;</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">import com.masetta.spann.spring.core.annotations.VisitMethods;</span> import com.masetta.spann.spring.core.annotations.VisitMethods;</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Component</span> @Составная часть</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@VisitMethods</span> @VisitMethods</span>
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public class Savana {</span> открытый класс Savana {</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">private AtomicInteger newElemphants = new AtomicInteger();</span> private AtomicInteger newElemphants = new AtomicInteger ();</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">private AtomicInteger newZebras = new AtomicInteger();</span> private AtomicInteger newZebras = new AtomicInteger ();</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@QuartzJob(name="zebraBorn",group="savana")</span> @QuartzJob (имя = "zebraBorn", группа = "Savana")</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Interval(repeatInterval=200)</span> @Interval (repeatInterval = 200)</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public void zebraBorn() {</span> public void zebraBorn () {</span>
  <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">newZebras.incrementAndGet();</span> newZebras.incrementAndGet ();</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>
 
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@QuartzJob(name="elephantBorn",group="savana")</span> @QuartzJob (имя = "elephantBorn", группа = "Savana")</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">@Cron(cronExpression="0/2 * * ? * * *")</span> @Cron (cronExpression = "0/2 * *? * * *")</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public void elephantBorn() {</span> public void elephantBorn () {</span>
  <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">newElemphants.incrementAndGet();</span> newElemphants.incrementAndGet ();</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public int getNewZebras() {</span> public int getNewZebras () {</span>
  <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">return newZebras.get();</span> return newZebras.get ();</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>
  
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">public int getNewElephants() {</span> public int getNewElephants () {</span>
  <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">return newElemphants.get();</span> return newElemphants.get ();</span>
 <span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>
 
<span class="notranslate" onmouseover="_tipon(this)" onmouseout="_tipoff()"><span class="google-src-text" style="direction: ltr; text-align: left">}</span> }</span>

Боб настраивается с помощью аннотации @Component пружины . Это обычный Spring bean-компонент, и любые Spring- или аспектные аннотации ( @Autowired , @Resource , @Transactional ) будут обрабатываться Spring.

По умолчанию spann обрабатывает только аннотации уровня класса; @VisitMethods инструктирует spann также посещать методы этого класса и обрабатывать их аннотации, если они есть.

Использование новых аннотаций не вызывает затруднений : каждый запланированный метод должен быть аннотирован как @QuartzJob (для создания делегирующего JobDetail ), так и аннотацией @Cron или @Interval (здесь не показано, но доступно в svn) для создания триггера. ,

Это также демонстрирует композицию аннотации spann, которая позволяет аннотациям быть гранулированными и подключаемыми: @QuartzJob может использоваться с любой аннотацией, которая конфигурирует компонент Trigger , в то время как @Cron и @Interval могут использоваться с любой аннотацией, которая конфигурирует компонент JobDetail .

Резюме

Spann — это расширение с открытым исходным кодом для среды Spring, которое позволяет выполнять расширенную настройку bean-компонентов с использованием аннотаций. Код демонстрирует использование аннотации spann @BeanConfig для создания запланированных заданий Quartz с использованием аннотаций.

В примере используется высокоуровневый API spann , а именно аннотация @BeanConfig , реализованная в самом проекте spann. Высокоуровневый API Spann включает другие аннотации, которые позволяют заменять методы (для реализации абстрактных методов во время выполнения, внутренне используя cglib), создание синтетических адаптеров и всестороннюю поддержку JPA-запросов.

Интеграция Spann с Spring очень тесная: он создает «простые старые bean-компоненты Spring », как те, которые определены в XML или аннотацией @Component . Это позволяет вам использовать все функции bean-компонентов Spring: бины могут быть получены через ApplicationContext в Spring , имеют нормальный жизненный цикл bean-компонента, могут быть постобработаны (например, для замены выражений), автоматически подключены, перехвачены с использованием аспектов, управляются с помощью JMX и т. Д. на. Вам не нужны хаки и обходные пути, и вам не нужно переопределять, копировать и корректировать существующий Spring-код. Кроме того, у вас меньше шаблонный код и меньше шаблонная конфигурация.

Как бы ни были гибки @BeanConfig и другие аннотации spann, существуют варианты использования, которые они не охватывают. Но низкоуровневый API Spann позволяет создавать новые аннотации с нуля, предоставляя разработчикам полный контроль над созданием и настройкой определений bean-компонентов. Вы даже можете использовать spann для обработки метаданных любого другого класса, реализовав свой собственный MetadataVisitor , опционально игнорируя аннотации все вместе.

Справка: интеграция Spring & Quartz с пользовательскими аннотациями — путь SPANN от нашего партнера по W4G Рона Питермана .

Статьи по Теме :