Interceptors
Василий Кряжев
[email protected]
Рассматриваемые темы
 Перехват методов бизнес
интерфейса
 Перехват событий жизненного
цикла
 Interceptors и обработка
исключений
1-2
Рассматриваемые темы
 Перехват методов бизнес
интерфейса
 Создание interceptor класса
 Применение interceptors
 Перехват событий жизненного
цикла
 Interceptors и обработка
исключений
1-3
Что неправильно?
Код профилирования “загрязняет”
бизнес логику
@Stateless
public class TodoListBean {
public void assignProject(Project project) {
long start = System.currentTimeMillis();
try {
// реализация бизнес логики
} finally {
long stop = System.currentTimeMillis();
log.write(“assignProject: ” + (stop - start) + “ (ms)”);
}
}
}
1-4
Interceptor методы
Декларирование через @AroundInvoke
package javax.interceptor;
@Target(METHOD) @Retention(RUNTIME)
public @interface AroundInvoke {}
// Сигнатура метода помеченного AroundInvoke
@AroundInvoke
Object method-name(javax.interceptor.InvocationContext
invocationContext) throws Exception;
1-5
Interceptor класс
Код профилирования после
рефакторинга
public class BeanProfiler {
@AroundInvoke
public Object timeMethod(InvocationContext ctx) throws Exception {
long start = System.currentTimeMillis();
try {
return ctx.proceed();
} finally {
long stop = System.currentTimeMillis();
log.write(“assignProject: ” + (stop - start) + “ (ms)”);
}
}
}
1-6
Контекст выполнения
Интерфейс InvocationContext
package javax.interceptor;
public interface InvocationContext {
java.lang.Object getTarget();
java.lang.reflect.Method getMethod();
java.lang.Object[] getParameters();
void setParameters(java.lang.Object[] objects);
java.util.Map<java.lang.String,java.lang.Object> getContextData();
java.lang.Object proceed() throws java.lang.Exception;
}
getContextData – данные которые можно совместно
использовать в процессе вызова бизнес метода
proceed – запускает следующий interceptor метод или сам
бизнес метод в конце цепочки
1-7
Применение interceptors
Применение на основе аннотаций:
package javax.interceptor;
@Target({TYPE, METHOD}) @Retention(RUNTIME)
public @interface Interceptors {
java.lang.Class[] value();
}
@Stateless
@Interceptors{BeanProfiler.class} // на уровне класса, для всех методов
public class TodoListBean {
}
@Stateless
public class TodoListBean {
@Interceptors{BeanProfiler.class} // на уровне метода
public void assignProject(Project project){…}
}
1-8
Применение interceptors
Применение через дескриптор
развертывания:
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TodoListBean</ejb-name>
<interceptor-class>com.acme.BeanProfiler</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TodoListBean</ejb-name>
<interceptor-class>com.acme.BeanProfiler</interceptor-class>
<method>
<method-name>assignProject</method-name>
<method-params>
<method-param>com.acme.Project</method-param>
</method-params>
</method>
</interceptor-binding>
</assembly-descriptor>
1-9
Interceptors по умолчанию
Применение interceptor для всех бинов
модуля ejb-jar используя символ “*”
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>com.acme.Logger</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>TodoListBean</ejb-name>
<interceptor-class>com.acme.BeanProfiler</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
1-10
Interceptors по умолчанию
Отключение перехватчиков
назначенных по умолчанию
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>com.acme.Logger</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>TodoListBean</ejb-name>
<interceptor-class>com.acme.BeanProfiler</interceptor-class>
<exclude-default-interceptors/>
</interceptor-binding>
</assembly-descriptor>
1-11
Interceptors и Injection
Инициализация ссылок через DI
@Stateless
public class AccessInterceptor {
@Resource EJBContext ejbContext;
@PersistenceContext(unitName = “ACCESS_DB”) EntityManager em;
}
@AroundInvoke public Object record(InvocationContext ctx) throws Exception {
AccessRecord record = new AccessRecord(new Date(),
ejbContext.getCallerPrincipal(), ejbContext.getMethod());
try{
ctx.proceed();
} catch (Exception e) {
record.setError(e);
throw e;
} finally {
em.pertsist(record);
}
}
1-12
Выводы
В этой секции мы узнали как:
 Создавать interceptor классы и
AroundInvoke методы
 Связывать interceptors с классами и
методами EJB
 Декларировать interceptors
используемые по умолчанию
 Инициализировать в interceptor
классах ссылки на ресурсы
1-13
Рассматриваемые темы
 Перехват методов бизнес
интерфейса
 Перехват событий жизненного
цикла
 Interceptors и обработка
исключений
1-14
События жизненного цикла
Аннотации жизненного цикла
@Stateless
public class OrderAgentBean
implements OrderAgentRemote, OrderAgentLocal {
@PostConstruct public void initialize() {
// obtain connections, files, streams
}
}
@PreDestroy public void cleanup() {
// close connections, files, streams
}
см. далее
1-15
События жизненного цикла
Аннотации жизненного цикла
 PrePassivate
 PostActivate
Сигнатура метода обработки события
жизненного цикла в классе реализации
идет без параметров и без блока throws
@callback-annotation
void metod-name();
1-16
События жизненного цикла
Обработка событий в Interceptor классе
Сигнатура метода обработки события
жизненного цикла в interceptor классе
@callback-annotation
void metod-name(InvocationContext ctx);
В interceptor классе может быть только
один метод для обработки события
каждого типа
1-17
События жизненного цикла
Пример цепочки событий
@Stateless @Interceptors(AccessInterceptor.class)
public class ShoppingCartBean implements ShoppingCart {
}
@PostConstruct public void startShoppingCart() { … }
public int someShoppingMethod() { … }
public class AccessInterceptor {
@PostConstruct public void startAccessEvent(InvocationContext ctx) {
// какие либо действия
ctx.proceed();
}
@AroundInvoke public Object record(InvocationContext ctx) {
// какие либо действия
ctx.proceed();
}
}
1-18
Рассматриваемые темы
 Перехват методов бизнес
интерфейса
 Перехват событий жизненного
цикла
 Interceptors и обработка
исключений
1-19
Обработка исключений
Изменение параметров вызова
public class JNDIServiceHandler{
@Resource String alternateUrl;
@AroundInvoke
public Object tryAlternateUrl(InvocationContext ctx)
throws Exception {
try {
return ctx.proceed();
} catch (javax.naming.ServiceUnavailableException e) {
Object[] newArgs = ctx.getParameters();
newArgs[0] = alternateUrl;
ctx.setParameters(newArgs);
return ctx.proceed();
}
}
}
1-20
Обработка исключений
Прекращение дальнейшей обработки
public class WithdrawalValidator {
@Resource int maxUnapprovedDebit;
@AroundInvoke
public Object validate(InvocationContext ctx)
throws Exception {
int amount = ctx.getParameters()[0];
if (amount > maxUnapprovedDebit)
throw new DebitLimitException(“Amount: ” + amount);
}
}
return ctx.proceed();
1-21
Обработка исключений
Преобразование исключений
@ApplicationException(rollback = true)
public class DbDeadlockException extends java.sql.SQLException { … }
public class SybaseErrorHandler {
@AroundInvoke
public Object narrowSQLException(InvocationContext ctx)
throws Exception {
try {
return ctx.proceed();
} catch (SQLException e) {
int errorCode = e.getErrorCode();
switch (errorCode) {
case 1205: throw new DbDeadlockException(e);
case 557: throw new DbInvalidCursorException(e);
}
}
}
}
1-22
Выводы
В этой секции мы узнали как:
 Ловить и обрабатывать
исключения в AroundInvoke
методах
 Использовать interceptors чтобы
предотвратить вызов бизнес
метода
 Использовать interceptors для
преобразования исключений
1-23
Практика
Упражнение
Вынос общего поведения в EJB
interceptor
1-24
Выводы
В этом модуле мы узнали как:
 Создавать и использовать
interceptor классы в EJB
 Создавать interceptors для
обработки событий жизненного
цикла
 Использовать interceptors при
обработке исключений
1-25
Скачать