Java EE 6允許我們通過CDI創建裝飾器,作為其AOP功能的一部分。 如果我們想實現仍然與業務足夠接近的跨領域關注點 ,則可以使用Java EE 6的此功能。
假設您有一項票務服務,可讓您訂購特定事件的票務。 TicketService處理注冊等,但是我們要添加餐飲。 我們不認為這是門票訂購邏輯的一部分,因此我們創建了一個裝飾器。 裝飾者將調用TicketService并添加門票數量。
界面:
public interface TicketService {Ticket orderTicket(String name);
}
接口的實現,創建票證并將其保留。
@Stateless
public class TicketServiceImpl implements TicketService {@PersistenceContextprivate EntityManager entityManager;@TransactionAttribute@Overridepublic Ticket orderTicket(String name) {Ticket ticket = new Ticket(name);entityManager.persist(ticket);return ticket;}
}
當我們不能使用裝飾器時,我們可以創建相同接口的新實現。
@Decorator
public class TicketServiceDecorator implements TicketService {@Inject@Delegateprivate TicketService ticketService;@Injectprivate CateringService cateringService;@Overridepublic 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{@Overridepublic Feed process(String feed) {System.out.println("processing this twitter feed");// processing logicsreturn new Feed(feed);}}
public class GooglePlusFeedProcessor implements SocialFeedProcessor {@Overridepublic Feed process(String feed) {System.out.println("processing this google+ feed");// processing logicsreturn new Feed(feed);}}
我將按照此處所述通過自定義限定符對這2個bean進行注釋
@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{@Overridepublic Feed process(String feed) {System.out.println("processing this twitter feed");// processing logicsreturn new Feed(feed);}}
@FeedProcessor
public class GooglePlusFeedProcessor implements SocialFeedProcessor {@Overridepublic Feed process(String feed) {System.out.println("processing this google+ feed");// processing logicsreturn new Feed(feed);}}
沒什么特別的,但是現在當我們編寫裝飾器時,我們使用CDI的功能僅用@FeedProcessor注釋裝飾類。
@Decorator
public class SocialFeedDecorator implements SocialFeedProcessor {@Delegateprivate @FeedProcessor SocialFeedProcessor processor;@Overridepublic 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的 高級用法 。
- JDK中的設計模式
- 在域驅動設計中使用狀態模式
- 基本的EJB參考,注入和查找
- 使用Spring AOP進行面向方面的編程
- 使用Spring AspectJ和Maven進行面向方面的編程
翻譯自: https://www.javacodegeeks.com/2011/10/java-ee6-decorators-decorating-classes.html