Java EE 6允许我们通过CDI创建装饰器,作为其AOP功能的一部分。 如果我们想实现仍然与业务足够接近的跨领域关注点 ,则可以使用Java EE 6的此功能。
假设您有一项票务服务,可让您订购特定事件的票务。 TicketService处理注册等,但是我们要添加餐饮。 我们不认为这是门票订购逻辑的一部分,因此我们创建了一个装饰器。 装饰者将调用TicketService并添加门票数量。
界面:
public interface TicketService {
Ticket orderTicket(String name);
}
接口的实现,创建票证并将其保留。
@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;
}
}
当我们不能使用装饰器时,我们可以创建相同接口的新实现。
@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批注(在注入点处)标记。 还要注意我们使用接口而不是实现的事实。
就像其他示例一样 ,当您注入此接口时,将使用常规实现。
@Inject private TicketService ticketService;
无需使用限定符,我们只需要调整beans.xml即可将TicketServiceDecorator标记为“ Decorator”。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>
作为更高级的用法,我们可以组合多个装饰器并选择我们希望它们执行的顺序。
如果您有用例,则可以像这样在bean.xml文件中定义两个装饰器,从而轻松定义它们。
<decorators>
<class>be.styledideas.blog.decorator.HighDecorator</class>
<class>be.styledideas.blog.decorator.LowDecorator</class>
</decorators>
因此,当我们调用装饰类时,我们会得到高级装饰器条目,低装饰器条目,实际装饰器类,低装饰器出口,高装饰器出口。 因此,文件中的装饰器顺序确实很重要。
第二个功能比第一个功能更具吸引力,它展示了Java EE6中Decorator功能的真正威力。 这是将其与CDI批注结合在一起的能力。 作为示例,我将使用社交媒体供稿处理器。
所以我创建了一个接口:
public interface SocialFeedProcessor {
Feed process(String feed);
}
并提供了2种实现,twitter和google +
public class TwitterFeedProcessor implements SocialFeedProcessor{
@Override
public Feed process(String feed) {
System.out.println("processing this twitter feed");
// processing logics
return new Feed(feed);
}
}
public class GooglePlusFeedProcessor implements SocialFeedProcessor {
@Override
public Feed process(String feed) {
System.out.println("processing this google+ feed");
// processing logics
return new Feed(feed);
}
}
@javax.inject.Qualifier
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Target({FIELD, PARAMETER, TYPE})
@java.lang.annotation.Documented
public @interface FeedProcessor {
}
然后用它注释我的两个处理器。
@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);
}
}
@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注释装饰类。
@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中注册装饰器
<decorators>
<class>be.styledideas.blog.decorator.SocialFeedDecorator</class>
</decorators>
通过使用注释,我们可以使用该装饰器自动装饰我们的SocialfeedProcessor的所有实现。 当我们添加不带注释的SocialFeedProcessor的额外实现时,将不装饰Bean。
参考: Java EE6装饰器,在注入时装饰类, Java EE6装饰器,来自Styled Ideas Blog的 JCG合作伙伴 Jelle Victoor的 高级用法 。
翻译自: https://www.javacodegeeks.com/2011/10/java-ee6-decorators-decorating-classes.html