Java EE 6 позволяет нам создавать декораторы через CDI, как часть их функций AOP . Если мы хотим реализовать сквозные задачи , которые все еще достаточно близки к бизнесу, мы можем использовать эту функцию Java EE 6.
Допустим, у вас есть служба заказа билетов, которая позволяет вам заказать билеты на определенное событие. Служба TicketService осуществляет регистрацию и т. Д., Но мы хотим добавить кейтеринг. Мы не рассматриваем это как часть логики заказа билетов, поэтому мы создали декоратор. Декоратор позвонит в TicketService и добавит питание по количеству билетов.
Интерфейс:
1
2
3
|
public interface TicketService { Ticket orderTicket(String name); } |
Реализация интерфейса создает тикет и сохраняет его.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Stateless public class TicketServiceImpl implements TicketService { @PersistenceContext private EntityManager entityManager; @TransactionAttribute @Override public Ticket orderTicket(String name) { Ticket ticket = new Ticket(name); entityManager.persist(ticket); return ticket; } } |
Когда мы не можем использовать декоратор, мы можем создать новую реализацию того же интерфейса.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Decorator public class TicketServiceDecorator implements TicketService { @Inject @Delegate private TicketService ticketService; @Inject private CateringService cateringService; @Override public Ticket orderTicket(String name) { Ticket ticket = ticketService.orderTicket(name); cateringService.orderCatering(ticket); return ticket; } } |
Обратите внимание, что здесь мы применяем 2 аннотации, специфичные для CDI. @Decorator отмечает реализацию как декоратор. У декоратора всегда должен быть делегат, класс, который мы хотим декорировать, помеченный аннотацией @Delegate (в точке внедрения). Также обратите внимание на то, что мы используем интерфейс, а не реализацию.
Как и в альтернативном примере , при внедрении этого интерфейса будет использоваться нормальная реализация.
1
|
@Inject private TicketService ticketService; |
Вместо того, чтобы использовать квалификаторы, нам просто нужно отрегулировать наш beans.xml, чтобы пометить TicketServiceDecorator как «Декоратор».
1
2
3
4
5
6
7
8
|
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd" > < decorators > < class >be.styledideas.blog.decorator.TicketServiceDecorator</ class > </ decorators > </ beans > |
В качестве более продвинутого использования мы можем объединить несколько декораторов и выбрать порядок их исполнения.
Если у вас есть сценарий использования, вы можете легко определить 2 декоратора, просто определив их в файле beans.xml следующим образом.
1
2
3
4
|
< decorators > < class >be.styledideas.blog.decorator.HighDecorator</ class > < class >be.styledideas.blog.decorator.LowDecorator</ class > </ decorators > |
Поэтому, когда мы вызываем наш декорированный класс, мы получаем запись высокого декоратора, низкий вход декоратора, фактический декорированный класс, низкий выход декоратора, выход высокого декоратора. Таким образом, последовательность декоратора в файле имеет значение.
Вторая функция более привлекательна, чем первая, она раскрывает истинную силу функции Decorator в Java EE6. Это возможность сочетать его с аннотациями CDI. В качестве примера я буду использовать процессор каналов социальных сетей.
Итак, я создал интерфейс:
1
2
3
|
public interface SocialFeedProcessor { Feed process(String feed); } |
и предоставили 2 реализации, твиттер и гугл +
01
02
03
04
05
06
07
08
09
10
|
public class TwitterFeedProcessor implements SocialFeedProcessor{ @Override public Feed process(String feed) { System.out.println( "processing this twitter feed" ); // processing logics return new Feed(feed); } } |
01
02
03
04
05
06
07
08
09
10
|
public class GooglePlusFeedProcessor implements SocialFeedProcessor { @Override public Feed process(String feed) { System.out.println( "processing this google+ feed" ); // processing logics return new Feed(feed); } } |
Я аннотирую эти 2 компонента с помощью специального классификатора, как описано здесь
1
2
3
4
5
6
|
@javax .inject.Qualifier @java .lang.annotation.Retention(RUNTIME) @java .lang.annotation.Target({FIELD, PARAMETER, TYPE}) @java .lang.annotation.Documented public @interface FeedProcessor { } |
и я аннотирую свои 2 процессора с ним.
01
02
03
04
05
06
07
08
09
10
11
|
@FeedProcessor public class TwitterFeedProcessor implements SocialFeedProcessor{ @Override public Feed process(String feed) { System.out.println( "processing this twitter feed" ); // processing logics return new Feed(feed); } } |
01
02
03
04
05
06
07
08
09
10
11
|
@FeedProcessor public class GooglePlusFeedProcessor implements SocialFeedProcessor { @Override public Feed process(String feed) { System.out.println( "processing this google+ feed" ); // processing logics return new Feed(feed); } } |
Ничего особенного, но теперь, когда мы пишем наш декоратор, мы используем мощь CDI, чтобы декорировать классы только с помощью аннотации @FeedProcessor.
01
02
03
04
05
06
07
08
09
10
11
|
@Decorator public class SocialFeedDecorator implements SocialFeedProcessor { @Delegate private @FeedProcessor SocialFeedProcessor processor; @Override public Feed process(String feed) { System.out.println( "our decorator is decorating" ); return processor.process(feed); } } |
осталось только зарегистрировать наш декоратор в файле beans.xml
1
2
3
|
<decorators> < class >be.styledideas.blog.decorator.SocialFeedDecorator</ class > </decorators> |
Используя аннотацию, мы автоматически украшаем все наши реализации SocialfeedProcessor этим декоратором. Когда мы добавляем дополнительную реализацию SocialFeedProcessor без аннотации, компонент не будет оформлен.
Справка: декораторы Java EE6, декорирование классов во время внедрения и декораторы Java EE6, расширенное использование от нашего партнера JCG Джелле Виктуор из блога Styled Ideas .