@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 { ... }
Назад | Вперёд | Содержание |