@Stateless
public class TimerBean {
...
@Schedule(minute="*/1", hour="*")
public void automaticTimerMethod() { ... }
@AroundTimeout
public void timeoutInterceptorMethod(InvocationContext ctx) { ... }
...
}
|
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
| Назад | Вперёд | Содержание |
Чтобы определить Interceptor, используйте одну из аннотаций метаданных Interceptor-а, перечисленных в таблице 57-1 внутри целевого класса или в отдельном классе Interceptor-а. Следующий код объявляет метод Interceptor-а @AroundTimeout в целевом классе:
@Stateless
public class TimerBean {
...
@Schedule(minute="*/1", hour="*")
public void automaticTimerMethod() { ... }
@AroundTimeout
public void timeoutInterceptorMethod(InvocationContext ctx) { ... }
...
}
Если вы используете классы Interceptor-ов, используйте аннотацию javax.interceptor.Interceptors, чтобы объявить один или несколько Interceptor-ов на уровне класса или метода целевого класса. Следующий код объявляет Interceptor-ы на уровне класса:
@Stateless
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class})
public class OrderBean { ... }
Следующий код объявляет класс Interceptor-а на уровне метода:
@Stateless
public class OrderBean {
...
@Interceptors(OrderInterceptor.class)
public void placeOrder(Order order) { ... }
...
}
Используйте аннотацию @AroundInvoke для обозначения методов Interceptor-ов для методов управляемого объекта. Для класса разрешается только один метод Interceptor-а типа Around-invoke. Методы Interceptor-а типа Around-invoke имеют следующую форму:
@AroundInvoke
visibility Object method-name(InvocationContext) throws Exception { ... }
Например:
@AroundInvoke
public void interceptOrder(InvocationContext ctx) { ... }
Методы Interceptor-а типа Around-invoke могут иметь публичный, приватный, защищённый или пакетный доступ и не должны объявляться как статические или final.
Interceptor типа Around-invoke может вызывать любой компонент или ресурс, вызывающийся целевым методом, может иметь тот же контекст безопасности и транзакции, что и целевой метод, и может работать в том же стеке вызовов виртуальной машины Java, что и целевой метод.
Interceptor-ы типа Around-invoke могут генерировать исключения во время выполнения и любое исключение, разрешённое предложением throws целевого метода. Они могут перехватывать и подавлять исключения, а затем восстанавливаться, вызывая метод InvocationContext.proceed.
Используйте аннотацию @Interceptors, чтобы объявить несколько Interceptor-ов для целевого метода или класса:
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class,
LastInterceptor.class})
public void updateInfo(String info) { ... }
Порядок Interceptor-ов в аннотации @Interceptors определяет порядок вызова Interceptor-ов.
Вы также можете определить несколько Interceptor-ов в дескрипторе развёртывания. Порядок Interceptor-ов в дескрипторе развёртывания определяет порядок, в котором будут вызываться Interceptor-ы:
...
<interceptor-binding>
<target-name>myapp.OrderBean</target-name>
<interceptor-class>myapp.PrimaryInterceptor.class</interceptor-class>
<interceptor-class>myapp.SecondaryInterceptor.class</interceptor-class>
<interceptor-class>myapp.LastInterceptor.class</interceptor-class>
<method-name>updateInfo</method-name>
</interceptor-binding>
...
Чтобы явно передать управление следующему Interceptor-у в цепочке, вызовите метод InvocationContext.proceed.
Данные могут быть разделены между Interceptor-ами.
Один и тот же объект InvocationContext передаётся в качестве входного параметра каждому методу Interceptor-а в цепочке Interceptor-ов для конкретного целевого метода. Свойство contextData объекта InvocationContext используется для передачи данных через методы Interceptor-а. Свойство contextData является объектом java.util.Map<String, Object>. Данные, хранящиеся в contextData, доступны для методов Interceptor-а далее по цепочке Interceptor-ов.
Данные, хранящиеся в contextData, не могут использоваться совместно для отдельных вызовов методов целевого класса. То есть для каждого вызова метода в целевом классе создаётся отдельный объект InvocationContext.
Вы можете использовать объект InvocationContext, передаваемый каждому методу типа Around-invoke, для доступа и изменения параметров целевого метода. Свойство parameters в InvocationContext представляет собой массив объектов Object, который соответствует порядку параметров целевого метода. Например, для следующего целевого метода свойство parameters в объекте InvocationContext, передаваемом методу Interceptor-а типа Around-invoke в PrimaryInterceptor, имеет вид массива Object, содержащий два объекта String (firstName и lastName) и объект Date (date):
@Interceptors(PrimaryInterceptor.class)
public void updateInfo(String firstName, String lastName, Date date) { ... }
Вы можете получить доступ к параметрам и изменить их с помощью методов InvocationContext.getParameters и InvocationContext.setParameters соответственно.
Interceptor-ы для событий Callback-вызова жизненного цикла (around-construct, post-construct и pre-destroy) могут быть определены в целевом классе или в классах Interceptor-ов. Аннотация javax.interceptor.AroundConstruct обозначает метод как метод Interceptor-а, который вставляется в вызов конструктора целевого класса. Аннотация javax.annotation.PostConstruct используется для обозначения метода в качестве Interceptor-а событий жизненного цикла post-construct. Аннотация javax.annotation.PreDestroy используется для обозначения метода в качестве Interceptor-а события жизненного цикла pre-destroy.
Interceptor-ы событий жизненного цикла, определённые в целевом классе, имеют следующую форму:
void method-name() { ... }
Например:
@PostConstruct
void initialize() { ... }
Interceptor-ы событий жизненного цикла, определённые в классе Interceptor-ов, имеют следующую форму:
void method-name(InvocationContext) { ... }
Например:
@PreDestroy
void cleanup(InvocationContext ctx) { ... }
Методы Interceptor-а жизненного цикла могут иметь публичный, приватный, защищённый или пакетный доступ и не должны объявляться как статические или final. Interceptor-ы жизненного цикла могут генерировать исключения во время выполнения, но не могут генерировать проверяемые исключения.
Методы Interceptor-а жизненного цикла вызываются в неопределённом контексте безопасности и транзакции. То есть переносимые приложения Java EE не должны предполагать, что метод Interceptor-а событий жизненного цикла имеет доступ к контексту безопасности или транзакции. Только один метод Interceptor-а для каждого события жизненного цикла (post-create и pre-destroy) разрешён для каждого класса.
Методы@AroundConstruct вставляются в вызов конструктора целевого класса. Методы, аннотированные @AroundConstruct, могут быть определены только внутри классов Interceptor-ов или родительских классов Interceptor-ов. Нельзя использовать методы @AroundConstruct в целевом классе.
Метод @AroundConstruct вызывается после завершения инъецирования всех Interceptor-ов, связанных с целевым классом. Целевой класс создаётся, и инъецирование конструктора целевого класса выполняется после того, как все связанные методы @AroundConstruct вызвали метод Invocation.proceed. В этот момент инъецирование зависимостей для целевого класса завершается, и затем выполняются вызовы Callback-метода @PostConstruct.
Методы @AroundConstruct могут обращаться к созданному целевому объекту после вызова Invocation.proceed путём вызова метода InvocationContext.getTarget.
Внимание: Вызов методов на целевом объекте из метода |
Методы@AroundConstruct должны вызывать Invocation.proceed для создания целевого объекта. Если метод @AroundConstruct не вызывает Invocation.proceed, целевой объект не будет создан.
Вы можете определить несколько Interceptor-ов жизненного цикла для целевого класса, указав классы Interceptor-ов в аннотации @Interceptors:
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class,
LastInterceptor.class})
@Stateless
public class OrderBean { ... }
Данные, хранящиеся в свойстве contextData у InvocationContext, не доступны для разных событий жизненного цикла.
Вы можете определить Interceptor-ы для методов тайм-аута сервиса таймера EJB, используя аннотацию @AroundTimeout для методов в целевом классе или в классе Interceptor-а. Разрешается только один метод @AroundTimeout на класс.
Interceptor-ы тайм-аута имеют следующую форму:
Object method-name(InvocationContext) throws Exception { ... }
Например:
@AroundTimeout
protected void timeoutInterceptorMethod(InvocationContext ctx) { ... }
Методы Interceptor-а тайм-аута могут иметь публичный, приватный, защищённый или пакетный доступ и не должны объявляться как статические или final.
Interceptor-ы тайм-аута могут вызывать любой компонент или ресурс, вызываемый целевым методом тайм-аута, и вызываются в той же транзакции и контексте безопасности, что и целевой метод.
Interceptor-ы тайм-аута могут обращаться к объекту таймера, связанному с целевым методом тайм-аута, с помощью метода getTimer объекта InvocationContext.
Вы можете определить несколько Interceptor-ов тайм-аута для данного целевого класса, указав классы Interceptor-ов, содержащие методы Interceptor-ов @AroundTimeout в аннотации @Interceptors на уровне класса.
Если целевой класс задаёт Interceptor-ы тайм-аута в классе Interceptor-а а также имеет метод Interceptor-а @AroundTimeout внутри самого целевого класса, Interceptor-ы тайм-аута в классах Interceptor-ов вызываются первыми, а затем определяются Interceptor-ы тайм-аута, определённые в целевом классе. Например, в следующем примере предположим, что классы PrimaryInterceptor и SecondaryInterceptor имеют методы Interceptor-а тайм-аута:
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class})
@Stateful
public class OrderBean {
...
@AroundTimeout
private void last(InvocationContext ctx) { ... }
...
}
Сначала будет вызван Interceptor тайм-аута в PrimaryInterceptor, затем Interceptor тайм-аута в SecondaryInterceptor и, наконец, метод last, определённый в целевом классе.
Типы привязки Interceptor-а — это аннотации, которые можно применять к компонентам, чтобы связать их с конкретным Interceptor-ом. Типы привязки Interceptor-а, как правило, представляют собой пользовательские типы аннотаций времени выполнения, которые определяют цель Interceptor-а. Используйте аннотацию javax.interceptor.InterceptorBinding в определении пользовательской аннотации и укажите цель с помощью @Target, задав один или несколько из TYPE ( Interceptor-ы уровня класса), METHOD (Interceptor-ы уровня метода), CONSTRUCTOR (Interceptor-ы вокруг конструктора) или любую другую допустимую цель:
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Inherited
pubic @interface Logged { ... }
Типы связывания с Interceptor-ами могут также применяться к другим типам связывания с Interceptor-ами:
@Logged
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Inherited
public @interface Secured { ... }
Аннотируйте класс Interceptor-а с типом привязки Interceptor-а и аннотацией @Interceptor, чтобы связать привязку Interceptor-а с классом Interceptor-а:
@Logged
@Interceptor
public class LoggingInterceptor {
@AroundInvoke
public Object logInvocation(InvocationContext ctx) throws Exception { ... }
...
}
Класс Interceptor-а может объявлять несколько типов привязки Interceptor-а, и более одного класса Interceptor-а может объявлять тип привязки Interceptor-а.
Если класс Interceptor-а перехватывает вызовы Callback-методов жизненного цикла, он может объявлять только типы привязки Interceptor-а с помощью Target(TYPE) или, в случае @AroundConstruct вызовов Callback-методов жизненного цикла, Target(CONSTRUCTOR).
Добавьте аннотацию типа привязки Interceptor-а к классу, методу или конструктору целевого компонента. Типы привязки Interceptor-ов применяются с использованием тех же правил, что и аннотации @Interceptor:
@Logged
public class Message {
...
@Secured
public void getConfidentialMessage() { ... }
...
}
Если компонент имеет привязку Interceptor-а на уровне класса, он не должен быть final или иметь какие-либо не-static, не-private final методы. Если к не-static, не-private методу применяется привязка Interceptor-а, он не должен быть final, а класс компонента не может быть final.
Если Interceptor-ов несколько, порядок их вызова определяется следующими правилами.
Interceptor-ы по умолчанию определены в дескрипторе развёртывания и вызываются первыми. Они могут указывать порядок вызова или переопределять порядок, указанный с помощью аннотаций. Interceptor-ы по умолчанию вызываются в том порядке, в котором они определены в дескрипторе развёртывания.
Порядок перечисления классов Interceptor-ов в аннотации @Interceptors определяет порядок вызова этих Interceptor-ов. Любые настройки @Priority для Interceptor-ов, перечисленные в аннотации @Interceptors, игнорируются.
Если класс Interceptor-а имеет родительские классы, Interceptor-ы, определённые в родительских классах, вызываются первыми, начиная с самого общего родительского класса.
Классы Interceptor-ов могут устанавливать приоритет методов Interceptor-ов, устанавливая значение в аннотации javax.annotation.Priority.
После вызова Interceptor-ов, определённых в классах Interceptor-ов, конструктор целевого класса, Interceptor-ы типа Around-invoke или тайм-аута запускаются в том же порядке, что и Interceptor-ы в аннотации @Interceptors.
Если целевой класс имеет родительские классы, любые Interceptor-ы, определённые в родительских классах, вызываются первыми, начиная с самого общего родительского класса.
Аннотация @Priority требует указание значения типа int. Чем меньше число, тем выше приоритет соответствующего Interceptor-а.
Замечание: Порядок вызова Interceptor-ов с одинаковым значением приоритета зависит от реализации. |
Класс javax.interceptor.Interceptor.Priority определяет константы приоритета, перечисленные в таблице 57-2.
Таблица 57-2 Константы приоритета Interceptor-ов
Приоритет Константа |
Значение |
Описание |
|
0 |
Interceptor-ы, определённые платформой Java EE и предназначенные для раннего вызова в цепочке вызовов, должны использовать диапазон между |
|
1000 |
Interceptor-ы, определённые библиотеками расширений, которые должны вызываться на ранних этапах цепочки Interceptor-ов, должны использовать диапазон между |
|
2000 |
Interceptor-ы, определённые приложениями, должны использовать диапазон между |
|
3000 |
Interceptor-ы с низким приоритетом, определённые библиотеками расширений, должны использовать диапазон между |
|
4000 |
Interceptor-ы с низким приоритетом, определённые платформой Java EE, должны иметь значения выше, чем |
Примечание: Отрицательные значения приоритета зарезервированы спецификацией Interceptor-ов для будущего использования и не должны использоваться. |
В следующем фрагменте кода показано, как использовать константы приоритета в определяемом приложением Interceptor-е:
@Interceptor
@Priority(Interceptor.Priority.APPLICATION+200
public class MyInterceptor { ... }
| Назад | Вперёд | Содержание |
Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены.
Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)