官术网_书友最值得收藏!

Using events

Events, as you may know, are runtime incidents that you do care about. CDI provides a loosely coupled model, following the observer design pattern, which allows you to fire an event from a CDI bean, and handling the event from one or more other CDI beans. The key advantages of the CDI events model are:

  • Event producers and observers are decoupled from each other
  • Observers can define selectors to limit the set of events they consume
  • Observers are aware of database transactions and can consume events according to transaction states

In our booking application, we are going to use events in order to notify end users by email with either the success or failure of their booking operations, without tightly coupling the mailing code with the business logic of the booking itself.

Let's start by defining our booking database model; in the next chapter, this will be persisted in a relational database:

public class Booking { 
 
    private long id; 
    private long cinemaId; 
    private long slotId; 
    private long filmId; 
    private List<Long> seatIds; 
    private BigDecimal amountPaid; 
 
    public Booking() { 
    } 
 
    public Booking(long id, long cinemaId, long slotId, long filmId, List<Long> seatIds, BigDecimal amountPaid) { 
        this.id = id; 
        this.cinemaId = cinemaId; 
        this.slotId = slotId; 
        this.filmId = filmId; 
        this.seatIds = seatIds; 
        this.amountPaid = amountPaid; 
    } 
 
    // getter and setter methods 
 
} 

Next, we will implement a booking notifier bean, which will represent the observer object for the booking event. The role of this object is to receive a signal when a booking operation has been made, then it prepares and sends an email to the end user confirming with them the booking details. The real code of sending email will be shown in Chapter 9, Sending Mails with JavaMail 1.6. For now, we will log a message to the application server console. Create a class with the name BookingNotifier and write the following code:

@Dependent 
public class BookingNotifier { 
 
    public void onBooking(@Observes Booking booking) { 
        System.out.println("New Booking with id " + booking.getId()); 
        // a notification mail should be sent to the user 
    } 
} 

As you have just noticed, the observer is no more than a normal CDI bean. What is special to events here is that we used the @Observers annotation on a parameter of a plain Java method; this tells the container that this method is interested in receiving the events regarding booking objects.

Now, when will this event be fired? Another CDI bean, whose role will be to actually perform the booking operation, will ask to notify all interested objects, as in the following code:

@Dependent 
public class BookingHandler { 
 
    private @Inject @Any Event<Booking> bookingEvent; 
 
    public void book(Booking booking) { 
        // do booking
        bookingEvent.fire(booking); 
    } 
} 

As you see, when the booking operation is performed, it will notify our observer about the booking incident, where it will take the appropriate action.

Note that we can define more observer objects, and all of them will be invoked upon firing this event, which is the role of the @Any annotation.

Now, let's complete our example by writing a servlet that simulates a user booking operation:

@WebServlet(urlPatterns = "/cdi-example") 
public class ExampleServlet extends HttpServlet { 
 
    @Inject 
    private BookingHandler bookingHandler; 
 
    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException { 
        Booking booking = new Booking(1234, 1, 122, 241, (List<Long>) Arrays.asList(1L, 2L, 3L), new BigDecimal("123")); 
        bookingHandler.book(booking); 
    } 
 
} 

By running the previous example, the output will be as follows:

New Booking with id 1234
Qualifying Events

Events can also be qualified, so we can propagate our event to a bean that is interested in a specific aspect of the event. Let's extend our example to design two types of events related to the booking operation, one for success, and the other for failure. There will be a bean that will react to the success event, where another one will react to the failure. We will define two qualifiers as follows:

@Qualifier 
@Retention(RUNTIME) 
@Target({TYPE, METHOD, FIELD, PARAMETER}) 
public @interface Success {} 
 
@Qualifier 
@Retention(RUNTIME) 
@Target({TYPE, METHOD, FIELD, PARAMETER}) 
public @interface Failure { 
 
} 

Then, we will replace @Any with the @Success annotation for the onBooking method, and write another one for @Failure as follows:

@Dependent 
public class BookingNotifier { 
 
    public void onBooking(@Observes @Success Booking booking) { 
        System.out.println("New Booking with id " + booking.getId()); 
        // a notification mail should be sent to the user 
    } 
 
    public void onBookingFailed(@Observes @Failure Booking booking) { 
        System.out.println("New Booking failed with id " + booking.getId()); 
        // a notification mail should be sent to the user 
    } 
} 

Now, we will inject two different event propagators in BookingHandler, one for the success, and the other for the failure, as follows:

@Dependent 
public class BookingHandler { 
 
    private @Inject @Success Event<Booking> bookingSuccessEvent; 
    private @Inject @Failure Event<Booking> bookingFailedEvent; 
 
    public void book(Booking booking) { 
        try { 
            // do booking 
            bookingSuccessEvent.fire(booking); 
        } catch (Exception e) { 
            // booking failed 
            bookingFailedEvent.fire(booking); 
        } 
    } 
} 

In the previous code, if the booking has been performed successfully, the success event will be fired, and the onBooking observer will be invoked. If some runtime errors occurred during the booking operation, the failure event will be fired, and the onBookingFailed observer will be invoked. This technique is very useful when we need to track different aspects of the same events in our enterprise application.

主站蜘蛛池模板: 湖南省| 神池县| 鸡泽县| 通州市| 石屏县| 澜沧| 汉沽区| 阿巴嘎旗| 宁化县| 齐河县| 太仓市| 鄯善县| 股票| 北流市| 南丰县| 曲水县| 西丰县| 津市市| 营口市| 吴堡县| 中牟县| 阿勒泰市| 喀喇沁旗| 宿州市| 枝江市| 若尔盖县| 定州市| 高阳县| 永丰县| 阜平县| 大足县| 三穗县| 容城县| 葫芦岛市| 白山市| 通许县| 洱源县| 徐州市| 郁南县| 扬中市| 花莲县|