Version 2

    &27726;&29992;&12452;&12531;&12479;&12475;&12503;&12479; (Generic Interceptor) 

     

    &12399;&12376;&12417;&12395; (Introduction)

    The runtime services, such as transaction and security services, are applied to the bean objects at the method invocation time. Under the hood, those services are often implemented as interceptor methods managed by the container, which run before and after the target method invocation to check for service actions (e.g., to commit a transaction or throw a security exception).

     

    &12488;&12521;&12531;&12470;&12463;&12471;&12519;&12531;&12420;&12475;&12461;&12517;&12522;&12486;&12451;&12469;&12540;&12499;&12473;&12398;&12424;&12358;&12394;&12521;&12531;&12479;&12452;&12512;&12469;&12540;&12499;&12473;&12399;&12289;&12513;&12477;&12483;&12489;&21628;&12403;&20986;&12375;&26178;&12395;Bean&12458;&12502;&12472;&12455;&12463;&12488;&12395;&23550;&12375;&12390;&36969;&29992;&12373;&12428;&12414;&12377;&12290;&20869;&37096;&12391;&12399;&12289;&12381;&12428;&12425;&12398;&12469;&12540;&12499;&12473;&12399;&12375;&12400;&12375;&12400;&12289;&12467;&12531;&12486;&12490;&12395;&12424;&12387;&12390;&31649;&29702;&12373;&12428;&12427;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12392;&12375;&12390;&23455;&35013;&12373;&12428;&12414;&12377;&12290;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12399;&12469;&12540;&12499;&12473;&12450;&12463;&12471;&12519;&12531;&12434;&34892;&12358;&12383;&12417; (&12383;&12392;&12360;&12400;&12488;&12521;&12531;&12470;&12463;&12471;&12519;&12531;&12434;&12467;&12511;&12483;&12488;&12375;&12383;&12426;&12475;&12461;&12517;&12522;&12486;&12451;&20363;&22806;&12434;&25237;&12370;&12427;&12383;&12417;)&12289;&23550;&35937;&12513;&12477;&12483;&12489;&12398;&21628;&12403;&20986;&12375;&21069;&24460;&12395;&23455;&34892;&12373;&12428;&12414;&12377;&12290;

     

    EJB 3.0 allows developers to write custom interceptors for EJB methods. That essentially gives you an extensible container. You can develop, reuse and ship your own services. Or, you can even re-implement the transaction and security services to override the container's default services offering. In this trail, we will discuss how EJB 3.0 interceptor works.

     

    EJB 3.0&12391;&12399;&38283;&30330;&32773;&12399;EJB&12513;&12477;&12483;&12489;&12398;&12383;&12417;&12395;&12459;&12473;&12479;&12512;&12452;&12531;&12479;&12475;&12503;&12479;&12434;&26360;&12367;&12371;&12392;&12364;&12391;&12365;&12414;&12377;&12290;&12371;&12428;&12399;&12467;&12531;&12486;&12490;&12364;&25313;&24373;&21487;&33021;&12391;&12354;&12427;&12371;&12392;&12434;&24847;&21619;&12375;&12390;&12356;&12414;&12377;&12290;&12354;&12394;&12383;&12399;&29420;&33258;&12398;&12469;&12540;&12499;&12473;&12434;&38283;&30330;&12289;&20877;&21033;&29992;&12289;&20986;&33655;&12377;&12427;&12371;&12392;&12364;&12391;&12365;&12414;&12377;&12290;&12354;&12427;&12356;&12399;&12488;&12521;&12531;&12470;&12463;&12471;&12519;&12531;&12420;&12475;&12461;&12517;&12522;&12486;&12451;&12469;&12540;&12499;&12473;&12434;&20877;&23455;&35013;&12375;&12289;&12467;&12531;&12486;&12490;&12398;&12487;&12501;&12457;&12523;&12488;&12469;&12540;&12499;&12473;&12364;&25552;&20379;&12377;&12427;&12418;&12398;&12434;&19978;&26360;&12365;&12377;&12427;&12371;&12392;&12373;&12360;&12391;&12365;&12414;&12377;&12290;&12371;&12398;&23567;&36947;&12391;&12399;&12289;EJB 3.0&12452;&12531;&12479;&12475;&12503;&12479;&12364;&12393;&12398;&12424;&12358;&12395;&20685;&12367;&12363;&12434;&35542;&12376;&12390;&12356;&12365;&12414;&12377;&12290;

     

    &12469;&12531;&12503;&12523;&12450;&12503;&12522;&12465;&12540;&12471;&12519;&12531; (The Sample Application)

    The sample application in this trail showcases two custom interceptors I developed for the session-based investment calculator. One interceptor limits the number of historic records to four. That is, if you click on the "calculate" button multiple times, you will only see up to 4 most recent calculation records below the calculator form. The other interceptor provides the trace and execution time for each bean method involved in the calculation. The trace is displayed at the bottom of the page.

     

    &12371;&12398;&23567;&36947;&12398;&12469;&12531;&12503;&12523;&12450;&12503;&12522;&12465;&12540;&12471;&12519;&12531;&12399;&12475;&12483;&12471;&12519;&12531;&12505;&12540;&12473;&12398;&25237;&36039;&35336;&31639;&12398;&12383;&12417;&12395;&38283;&30330;&12375;&12383;2&12388;&12398;&12459;&12473;&12479;&12512;&12452;&12531;&12479;&12475;&12503;&12479;&12434;&32057;&20171;&12375;&12414;&12377;&12290;&12402;&12392;&12388;&30446;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12399;&35336;&31639;&12524;&12467;&12540;&12489;&12398;&23653;&27508;&25968;&12434;4&12388;&12395;&21046;&38480;&12375;&12414;&12377;&12290;&12300;&35336;&31639;&12301;&12508;&12479;&12531;&12434;&35079;&25968;&22238;&25276;&12375;&12383;&12392;&12365;&12289;&35336;&31639;&12501;&12457;&12540;&12512;&12398;&19979;&12395;&34920;&31034;&12373;&12428;&12427;&30452;&36817;&12398;&35336;&31639;&12524;&12467;&12540;&12489;&12364;4&12388;&12414;&12391;&12375;&12363;&34920;&31034;&12373;&12428;&12394;&12356;&12371;&12392;&12364;&12431;&12363;&12427;&12391;&12375;&12423;&12358;&12290;&12418;&12358;&19968;&26041;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12399;&35336;&31639;&12450;&12503;&12522;&12465;&12540;&12471;&12519;&12531;&12395;&21547;&12414;&12428;&12427;Bean&12398;&21508;&12513;&12477;&12483;&12489;&12398;&12488;&12524;&12540;&12473;&12392;&20966;&29702;&26178;&38291;&12434;&25552;&20379;&12375;&12414;&12377;&12290;&12488;&12524;&12540;&12473;&12399;&12506;&12540;&12472;&12398;&26368;&19979;&37096;&12395;&34920;&31034;&12373;&12428;&12414;&12377;&12290;

     

    Bean&12463;&12521;&12473;&20869;&12398;&12452;&12531;&12479;&12475;&12503;&12479; (Interceptor inside the bean class)

    You can place a custom interceptor method inside the bean class. The method must be annotated with the @AroundInvoke tag and it is called by the container before any other business method in the bean object is invoked. The container passes the current invocation context to the interceptor method as the ctx object. From the invocation context, you can figure out the current bean object and the target method intercepted by this interceptor. In the following example, the interceptor method inspects whether there are more than 4 cached records in this session. If so, it erases the earliest record to make room for the new calculation record. The ctx.proceed() statement at the end of the method recursively instructs the runtime to move on to the next interceptor. If there is no more interceptors, the target method is executed.

     

    &12459;&12473;&12479;&12512;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12399;Bean&12463;&12521;&12473;&20869;&12395;&32622;&12367;&12371;&12392;&12364;&12391;&12365;&12414;&12377;&12290;&12513;&12477;&12483;&12489;&12399;@AroundInvoke&12479;&12464;&12391;&12450;&12494;&12486;&12540;&12488;&12373;&12428;&12394;&12369;&12428;&12400;&12394;&12426;&12414;&12379;&12435;&12290;&12371;&12398;&12513;&12477;&12483;&12489;&12399;Bean&12458;&12502;&12472;&12455;&12463;&12488;&20869;&12398;&20182;&12398;&12499;&12472;&12493;&12473;&12513;&12477;&12483;&12489;&12364;&21628;&12403;&20986;&12373;&12428;&12427;&21069;&12395;&12289;&12467;&12531;&12486;&12490;&12363;&12425;&21628;&12400;&12428;&12414;&12377;&12290;&12467;&12531;&12486;&12490;&12399;&29694;&22312;&12398;&21628;&12403;&20986;&12375;&12467;&12531;&12486;&12461;&12473;&12488;&12434;ctx&12458;&12502;&12472;&12455;&12463;&12488;&12392;&12375;&12390;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12395;&28193;&12375;&12414;&12377;&12290;&21628;&12403;&20986;&12375;&12467;&12531;&12486;&12461;&12473;&12488;&12363;&12425;&12289;&29694;&22312;&12398;Bean&12458;&12502;&12472;&12455;&12463;&12488;&12392;&12289;&12371;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12395;&12424;&12387;&12390;&12452;&12531;&12479;&12475;&12503;&12488;&12373;&12428;&12383;&23550;&35937;&12513;&12477;&12483;&12489;&12364;&20998;&12363;&12426;&12414;&12377;&12290;&27425;&12398;&20363;&12391;&12399;&12289;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12399;&12289;&12475;&12483;&12471;&12519;&12531;&20869;&12395;4&12388;&12434;&36229;&12360;&12383;&35336;&31639;&35352;&37682;&12364;&12461;&12515;&12483;&12471;&12517;&12373;&12428;&12390;&12356;&12394;&12356;&12363;&26908;&26619;&12375;&12414;&12377;&12290;&12418;&12375;&12381;&12358;&12391;&12354;&12428;&12400;&12289;&12452;&12531;&12479;&12475;&12503;&12479;&12399;&26368;&12418;&21476;&12356;&35352;&37682;&12434;&28040;&12375;&12289;&26032;&12375;&12356;&35336;&31639;&35352;&37682;&12398;&12383;&12417;&12398;&22580;&25152;&12434;&31354;&12369;&12414;&12377;&12290;&12513;&12477;&12483;&12489;&12398;&26368;&24460;&12395;&26360;&12363;&12428;&12383;ctx.proceed()&12399;&20877;&24112;&30340;&12395;&27425;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12395;&36914;&12416;&12371;&12392;&12434;&25351;&31034;&12375;&12414;&12377;&12290;&12371;&12428;&20197;&19978;&12452;&12531;&12479;&12475;&12503;&12479;&12364;&12394;&12369;&12428;&12400;&12289;&23550;&35937;&12513;&12477;&12483;&12489;&12364;&23455;&34892;&12373;&12428;&12414;&12377;&12290;

     

     @Stateful
     public class InterceptorCalculator implements Calculator, Serializable {
     
       // ... ...
       
       @AroundInvoke
       public Object limitStateSize (InvocationContext ctx)
                                           throws Exception {
     
         // Remove the earliest entry when the history
         // list gets too long
         if (starts.size() > 4) {
           starts.remove (0);
           ends.remove (0);
           growthrates.remove (0);
           savings.remove (0);
           results.remove (0);
         }
         return ctx.proceed();
       }
     }
    

     

    &12452;&12531;&12479;&12475;&12503;&12479;&12463;&12521;&12473; (Interceptor class)

    Another way to define interceptors is to put the interceptor method in a separate class and then annotate the target bean class with the @Interceptor tag. Here is an interceptor class that logs the call trace and execution time of all the method invocation in its target bean object. Recall that the ctx.proceed() call in the interceptor recursively invokes the next interceptor and the target method. Hence, the code in the finally is called after the target and downstream interceptors are all returned.

     

    &12452;&12531;&12479;&12475;&12503;&12479;&12434;&23450;&32681;&12377;&12427;&12418;&12358;&12402;&12392;&12388;&12398;&12420;&12426;&26041;&12399;&12289;&21029;&12398;&12463;&12521;&12473;&12395;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12434;&32622;&12365;&12289;@Interceptor&12479;&12464;&12391;&23550;&35937;Bean&12463;&12521;&12473;&12434;&12450;&12494;&12486;&12540;&12488;&12377;&12427;&12371;&12392;&12391;&12377;&12290;&27425;&12398;&12467;&12540;&12489;&12399;&12289;&23550;&35937;Bean&12458;&12502;&12472;&12455;&12463;&12488;&12398;&20840;&12513;&12477;&12483;&12489;&21628;&12403;&20986;&12375;&12398;&21628;&12403;&20986;&12375;&12488;&12524;&12540;&12473;&12392;&23455;&34892;&26178;&38291;&12434;&12525;&12464;&20986;&21147;&12377;&12427;&12452;&12531;&12479;&12475;&12503;&12479;&12463;&12521;&12473;&12391;&12377;&12290;&12452;&12531;&12479;&12475;&12503;&12479;&20869;&12398;ctx.proceed()&12399;&27425;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12392;&23550;&35937;&12513;&12477;&12483;&12489;&12434;&20877;&24112;&30340;&12395;&21628;&12403;&20986;&12377;&12371;&12392;&12434;&24605;&12356;&20986;&12375;&12390;&12367;&12384;&12373;&12356;&12290;&12394;&12398;&12391;&12289;finally&20869;&12398;&12467;&12540;&12489;&12399;&12289;&23550;&35937;&12513;&12477;&12483;&12489;&12392;&19979;&27969;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12364;&12377;&12409;&12390;&36820;&12387;&12383;&24460;&12395;&21628;&12400;&12428;&12414;&12377;&12290;

     

     public class Tracer {
     
       @AroundInvoke
       public Object log (InvocationContext ctx)
                                 throws Exception {
     
         String className = ctx.getBean().getClass().getName();
         String methodName = ctx.getMethod().getName();
         String target = className + "." + methodName + "()";
     
         long start = System.currentTimeMillis();
         System.out.println ("Invoking " + target);
         try {
           return ctx.proceed();
         } catch(Exception e) {
           throw e;
         } finally {
           System.out.println("Exiting " + target);
           cal.setTrace(cal.getTrace() + "" +
                        "Exiting " + target);
           long time = System.currentTimeMillis() - start;
           System.out.println("This method takes " +
                               time + "ms to execute");
         }
       }
     }
    

     

    Here is the @Interceptor annotation on the bean class.

     

    &27425;&12399;Bean&12463;&12521;&12473;&12398;@Interceptor&12450;&12494;&12486;&12540;&12471;&12519;&12531;&12391;&12377;&12290;

     

     @Stateful
     @Interceptors (Tracer.class)
     public class InterceptorCalculator implements Calculator, Serializable {
     
       // ... ...
     }
    

     

    You can also use the @Interceptors annotation to specify multiple interceptor classes for the bean. Those interceptors are invoked in the order they appear on the annotation's attribute array. The interceptor method inside the bean class is invoked the last.

     

    @Interceptors&12450;&12494;&12486;&12540;&12471;&12519;&12531;&12434;&20351;&12387;&12390;&12289;Bean&12395;&35079;&25968;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12463;&12521;&12473;&12434;&25351;&23450;&12377;&12427;&12371;&12392;&12418;&12391;&12365;&12414;&12377;&12290;&12381;&12428;&12425;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12399;&12450;&12494;&12486;&12540;&12471;&12519;&12531;&12398;&23646;&24615;&37197;&21015;&12395;&29694;&12428;&12427;&38918;&12395;&21628;&12403;&20986;&12373;&12428;&12414;&12377;&12290;Bean&12463;&12521;&12473;&20869;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12399;&26368;&24460;&12395;&21628;&12403;&20986;&12373;&12428;&12414;&12377;&12290;

     

    &23436;&20840;&12394;&12477;&12540;&12473;&12467;&12540;&12489; (Complete source code)

    Server

     

    &12469;&12540;&12496;

     

    Calculator.java: The session bean interface

     

    &12475;&12483;&12471;&12519;&12531;Bean&12452;&12531;&12479;&12540;&12501;&12455;&12540;&12473;

     

    InterceptorCalculatorBean.java: The session bean with the history cache size limit interceptor method

     

    &23653;&27508;&12398;&12461;&12515;&12483;&12471;&12517;&12469;&12452;&12474;&12434;&21046;&38480;&12377;&12427;&12452;&12531;&12479;&12475;&12503;&12479;&12513;&12477;&12483;&12489;&12434;&25345;&12387;&12383;&12475;&12483;&12471;&12519;&12531;Bean

     

    Tracer.java: The interceptor class for the logging and tracing interceptor

     

    &12525;&12462;&12531;&12464;&12289;&12488;&12524;&12540;&12471;&12531;&12464;&12452;&12531;&12479;&12475;&12503;&12479;&12398;&12383;&12417;&12398;&12452;&12531;&12479;&12475;&12503;&12479;&12463;&12521;&12473;

     

    Client

     

    &12463;&12521;&12452;&12450;&12531;&12488;

     

    calculator.jsp: The JSP user interface

     

    JSP&12518;&12540;&12470;&12452;&12531;&12479;&12540;&12501;&12455;&12540;&12473;

     

    &12414;&12392;&12417; (Summary)

    In this trail, you learn how to use EJB 3.0 interceptors to expand the reach of container services. So far, we have covered pretty much all aspects of the EJB 3.0 specification and JBoss's extension APIs.

     

    &12371;&12398;&23567;&36947;&12391;&12399;&12289;&12467;&12531;&12486;&12490;&12469;&12540;&12499;&12473;&12398;&38936;&22495;&12434;&25313;&24373;&12377;&12427;&12383;&12417;&12289;EJB 3.0&12452;&12531;&12479;&12475;&12503;&12479;&12398;&20351;&12356;&26041;&12434;&23398;&12403;&12414;&12375;&12383;&12290;&12371;&12371;&12414;&12391;&12391;&12289;EJB 3.0&20181;&27096;&12392;JBoss&12398;&25313;&24373;API&12398;&22806;&35251;&12434;&12411;&12412;&12377;&12409;&12390;&12459;&12496;&12540;&12375;&12383;&12371;&12392;&12395;&12394;&12426;&12414;&12377;&12290;

     

    © 2005 JBoss, Inc. All Rights Reserved