08 апреля 2019
Java ЕЕ предоставляет нам хороший механизм для обработки событий, который является частью CDI для спецификации Java EE. Динамический CDI спецификатор может быть полезен для обработки событий, например, в domain driven архитектуре или при маршрутизации сообщений веб-сокета и т.д.
Генерация простого события:
@Named
public class MyEventSource {
@Inject
private Event<String> myEvent;
public void fireEvent(){
myEvent.fire("Hello World!");
}
}
Наблюдатель события:
@Named
public class MyEventObserver {
public void observeEvent(@Observes String message){
System.out.println(message);
}
}
Используя CDI спецификатор, можно определить, какой наблюдатель должен обработать событие
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Important {
}
Например:
@Named
public class MyEventSource {
@Inject
@Important
private Event<String> myEvent;
...
@Named
public class MyEventObserver {
public void observeEvent(@Observes @Important String message){
...
По-умолчанию, событие будет обработано обсервером в текущей транзакции, но можно изменить это поведение, используя @Observes
атрибут during
@Named
public class TransactionEventObserver {
public void observeImportantMessage(@Observes(during = TransactionPhase.AFTER_SUCCESS) String message){
System.out.println(message);
}
}
Доступны следующие значения:
Теперь давайте посмотрим как можно квалифицировать CDI события динамически. В примере ниже мы создадим обсервер для обработки пользовательских событий (вход в систему, выход, регистрация и т.д.), полученных из некого абстрактного источника.
Итак, сначала нам нужно создать Qualifier
с доступными значениями событий
@Qualifier
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Retention(RUNTIME)
public @interface UserEvent {
Routes value();
}
где Routes - это enum с доступными значениями, например:
public enum Routes {
LOGIN,
LOGOUT,
REGISTRATION
}
Потом нам нужно создать дочерний от javax.enterprise.util.AnnotationLiteral
класс для возможности использования квалификатора динамически.
public class UserEventBinding extends AnnotationLiteral<UserEvent> implements UserEvent {
Routes routes;
public UserEventBinding(Routes routes) {
this.routes = routes;
}
@Override
public Routes value() {
return routes;
}
}
Теперь давайте сгенерируем событие, используя динамический выбор наблюдателей
@Named
public class UserEventSource {
@Inject
private Event<String> userEvent;
public void fireEvent(Routes route){
userEvent.select(new UserEventBinding(route)).fire("Instead of string you can use your object");
}
}
Время показать, как выглядит наш Observer.
import static Routes.*;
...
@Named
public class UserObserver {
public void registration(@Observes @UserEvent(REGISTRATION) String eventData) {
....
}
public void login(@Observes @UserEvent(LOGIN) String eventData) {
....
}
public void logout(@Observes @UserEvent(LOGOUT) String eventData) {
....
}
}
P.S. В Java EE 8 с CDI 2.0 вы можете использовать асинхронные события CDI с помощью метода fireAsync
и аннотации @ObserveAsync
26 марта 2019
По умолчанию подсистема Undertow в Wildfly AS настроена на обработку запросов с max-post-size
= 10MB. В случае, если ваш запрос, больше, чем 10 МБ, вы получите
java.io.IOException: UT000020: Connection terminated as request was larger than 10485760
Для увеличения этого параметра, можно отредактировать непосредственно standalone
или domain
конфигурации
<subsystem xmlns="urn:jboss:domain:undertow:3.1">
<buffer-cache name="default"/>
<server name="default-server">
<http-listener name="default" socket-binding="http" max-post-size="15728640" redirect-socket="https" enable-http2="true"/>
<https-listener name="https" socket-binding="https" max-post-size="15728640" security-realm="SSLRealm"/>
....
или используйте команды CLI как показано ниже:
/subsystem=undertow/server=default-server/http-listener=default/:write-attribute(name=max-post-size,value=15728640)
/subsystem=undertow/server=default-server/https-listener=https/:write-attribute(name=max-post-size,value=15728640)
Заметьте! Если Вы используете Wildfly в доменном режиме с балансировщиком нагрузки AJP, вам также может потребоваться изменить max-post-size
для ajp-listener
/subsystem=undertow/server=default-server/ajp-listener=ajp/:write-attribute(name=max-post-size,value=15728640)
20 марта 2019
Опубликовано мое второе видео на YouTube (о Hibernate Search и интеграции с Wildfly)!
16 марта 2019
Для выполнения условной логики в SQL SELECT
, можно использовать выражение CASE
. Следующий SQL хак позволит вам выполнить условный count()
для вашего запроса.
Например, чтобы выбрать количество записей с id > 5
:
SQL:
SELECT SUM(CASE WHEN id > 5 THEN 1 ELSE 0 END) FROM Table
JPQL:
entityManager.createQuery("SELECT SUM(CASE WHEN b.id > 5 THEN 1 ELSE 0 END) FROM BlogEntity b").getSingleResult()
Criteria API:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Number> query = cb.createQuery(Number.class);
Root<BlogEntity> blogEntity = query.from(BlogEntity.class);
query.select(
cb.sum(
cb.<Number>selectCase()
.when(cb.gt(blogEntity.get("id"), 5), 1)
.otherwise(0)
)
);
Number result = em.createQuery(query).getSingleResult();
Исходный код, доступен на GitHub
15 марта 2019
SSH тоннель позволяет перенаправлять локальный трафик через SSH на удаленный хост. Может быть использован, например, для соедиения с удаленным приложением, которое было запущено на локальном порту удаленного хоста.
Например, чтобы соединиться с mysql, который был запущен на локальном порту 3306
хоста remotehost.com, вы можете использовать:
ssh -L 3366:localhost:3306 [USERNAME]@remotehost.com
или с использованием SSH keys :
ssh -i [KEY_FILENAME] -L 3366:localhost:3306 [USERNAME]@remotehost.com
После этого, вы можете соединиться с базой, используя любимый тулинг на localhost:3366