Статьи

Учебник и пример Java EE EJB Interceptors

В этом примере мы увидим, как использовать перехватчики в EJB и протестировать его с помощью простого веб-приложения.

1. Введение

Перехватчики используются, как следует из названия, когда вы хотите перехватить вызовы методов EJB. Если вы объявляете Перехватчик для Бина, каждый раз, когда вызывается метод этого Бина, он будет перехвачен одним методом Перехватчика. Это означает, что выполнение идет прямо к методу Перехватчика. Затем метод перехвата может решить, вызывать ли перехваченный метод EJB или просто заменить его.

Вы могли бы найти вышеупомянутое поведение, напоминающее философию Аспектно-ориентированного программирования, и вы были бы правы. Несмотря на то, что реализация двух технологий совершенно различна, правда в том, что они могут использоваться для одних и тех же целей. Например, когда вы хотите записать что-то до или после того, как будет выполнен метод Beans. Или когда вы хотите применить определенную политику в отношении вызовов методов, например, аутентификацию, проверку ввода и т. Д. Конечно, EJB может иметь цепочку перехватчиков, которые будут перехватывать метод в определенном порядке.

В этом примере мы собираемся создать проект EAR и проект EJB, в котором будут размещаться наши EJB и перехватчики, а также динамическое веб-приложение, в котором будет размещаться сервлет для проверки вышеупомянутого поведения. В качестве нашего контейнера мы будем использовать Eclipse Java EE IDE 4,3 Kepler и Glassfish 4.0.

2. Создайте новый проект корпоративного приложения

Создайте новый проект приложения предприятия с именем EJBInterceptorEAR В Eclipse IDE выберите «Файл» -> «Создать» -> «Проект приложения предприятия», заполните форму и нажмите «Готово»:

новое ухо-проект

3. Создайте новый EJB Projet

Создайте новый проект EJB под названием InterceptorsEJB . Мы собираемся создать наш сессионный компонент по этому вопросу. Перейдите в File -> New -> EJB Project и заполните форму. Будьте внимательны, выберите «Добавить проект EAR» и выберите « EJBInterceptorEAR » в качестве имени проекта EAR:

новый EJB-projecct

Дважды нажмите Next и выберите создание JAR ejb-jar.xml EJB-клиента, а также создание дескриптора развертывания ejb-jar.xml :

4. Создайте простой класс Interceptor

Мы собираемся определить простой Interceptor, который имеет только один метод. В проекте ejbModule папке ejbModule создайте новый пакет с именем com.javacodegeeks.enterprise.ejb.interceptor и создайте следующий класс:

SimpleInterceptor.java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.javacodegeeks.enterprise.ejb.interceptor;
 
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
 
public class SimpleInterceptor {
 
    @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {
 
        System.out.println("SimpleInterceptor - Logging BEFORE calling method :"+context.getMethod().getName() );
 
        Object result = context.proceed();
 
        System.out.println("SimpleInterceptor - Logging AFTER calling method :"+context.getMethod().getName() );
 
        return result;
    }
}

Обратите внимание, что public Object intercept аннотированный @AroundInvoke . Это означает, что этот конкретный метод будет перехватывать вызов метода EJB. Важно учитывать тот факт, что класс-перехватчик может иметь любое количество методов, но только один из них может быть аннотирован @AroundInvoke .

Вы можете использовать аргумент InvocationContext метода intercept для двух целей. Вы можете либо извлечь полезную информацию о перехваченном EJB-методе (например, мы использовали getMethod().getName() API getMethod().getName() для получения имени перехваченного метода), либо вы можете продолжить выполнение с помощью API continue proceed() метод. Этот метод переключит поток выполнения на следующий перехватчик в цепочке или на фактический перехваченный метод EJB, если в цепочке не осталось перехватчиков. Этот метод вернет результат вызова метода EJB. Но мы не знаем возвращаемый тип, поэтому proceed() возвращает экземпляр Object . Если вы знаете возвращаемый тип EJB-метода, вы можете привести результат proceed() к этому конкретному типу, а затем использовать этот экземпляр по своему усмотрению. Обратите внимание, что метод intercept также возвращает результат фактического вызова EJB. Это будет либо передано следующему перехватчику в цепочке перехватчиков, либо клиенту, если не осталось других перехватчиков.

Таким образом, любая бизнес-логика, которую вы хотите выполнить перед вызовом фактического метода EJB, должна быть размещена перед вызовом proceed() . Следовательно, вы помещаете код, который хотите выполнить, после выполнения фактического метода EJB, после вызова proceed() . Конечно, вы можете обойти обычное выполнение метода EJB все вместе, если хотите.

4. Создайте простой EJB

Вот EJB, который будет использовать вышеупомянутый Interceptor для перехвата его методов. В проекте ejbModule папке ejbModule создайте новый пакет с именем com.javacodegeeks.enterprise.ejb и создайте следующий класс:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package com.javacodegeeks.enterprise.ejb;
 
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
 
import com.javacodegeeks.enterprise.ejb.interceptor.SimpleInterceptor;
 
@Stateless
@Interceptors(SimpleInterceptor.class)
public class SimpleEJB {
 
    public String printMessage(String message) {
 
        System.out.println(" Executing method : printMessage" + message);
        return "Message is "+message;
    }
 
}

Как видите, мы пометили класс аннотацией @Interceptors(SimpleInterceptor.class) . Это означает, что все методы этого класса будут перехвачены SimpleInterceptor

Давайте создадим простой Servlet для проверки желаемой функциональности.

5. Создайте новый динамический веб-проект

Перейдите в Файл -> Создать -> Динамический веб-проект. Заполните форму и убедитесь, что вы EJBInterceptorEAR «Добавить проект в EAR» и поместили EJBInterceptorEAR в качестве «имени проекта EAR»:

новые динамический веб-приложения

После нажатия «Готово» перейдите в проводник проекта и щелкните правой кнопкой мыши по проекту InterceptorTesting и перейдите в Свойства-> Сборка развертывания -> Добавить -> Объект -> EJBInterceptorEAR :

Развертывание сборки

6. Создайте новый сервлет

Перейдите в веб-проект InterceptorTesting и создайте новый TestSerlvet именем TestSerlvet :

новый serlvet

Давайте посмотрим код этого сервлета:

TestServlet.java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.javacodegeeks.enterprise.servlet;
 
import java.io.IOException;
 
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.javacodegeeks.enterprise.ejb.SimpleEJB;
 
@WebServlet("/TestSerlvet")
public class TestSerlvet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    public TestSerlvet() {
        super();
 
    }
 
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Hello from Servlet");
 
        InitialContext ic;
        SimpleEJB bean;
 
        String message = request.getParameter("printMessage");
 
        if (message != null) {
 
            try {
 
                ic = new InitialContext();
                bean = (SimpleEJB) ic
                        .lookup("java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB!"
                                + "com.javacodegeeks.enterprise.ejb.SimpleEJB");
 
                bean.printMessage(message);
 
            } catch (NamingException e) {
 
                e.printStackTrace();
            }
        }
    }
}

Как видите, мы просто анализируем параметр запроса printMessage и передаем его значение в метод SimpleEJB из SimpleEJB .

Совет: Если у вас возникли проблемы с определением имен Portable JNDI для EJB PassivationObject, посмотрите журналы или выходные данные Glassfish при развертывании проекта, и вы обнаружите строку, подобную этой: 2014-01-09T15: 14: 14.627 + 0200 | INFO : EJB5181: Переносимые имена JNDI для EJB SimpleEJB: java: global / EJBInterceptorEAR / InterceptorTesting / SimpleEJB!
com.javacodegeeks.enterprise.ejb.SimpleEJB, Java: глобальный / EJBInterceptorEAR / InterceptorTesting / SimpleEJB)

7. Тест

Вы можете развернуть свое приложение на Glassfish и выполнить следующий запрос:

1
http://localhost:8080/InterceptorTesting/TestSerlvet?printMessage=Hello%20From%20JCG

Если вы посмотрите вывод Glassfish на консоли, вы увидите:

 2014-01-09T17:43:14.356+0200|INFO: Hello from Servlet 2014-01-09T17:43:14.357+0200|INFO: Logging BEFORE calling method :printMessage 2014-01-09T17:43:14.357+0200|INFO: Executing method : printMessage : Hello From JCG 2014-01-09T17:43:14.357+0200|INFO: Logging AFTER calling method :printMessage 

8. Несколько перехватчиков

Создайте еще один новый Interceptor в проекте InterceptorsEJB в пакете com.javacodegeeks.enterprise.ejb.interceptor .

Вот :

SecondInterceptor.java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.javacodegeeks.enterprise.ejb.interceptor;
 
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
 
public class SecondInterceptor {
 
    @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {
 
        System.out.println("SecondInterceptor - Logging BEFORE calling method :"+context.getMethod().getName() );
 
        Object result = context.proceed();
 
        System.out.println("SecondInterceptor  -Logging AFTER calling method :"+context.getMethod().getName() );
 
        return result;
    }
}

А вот и SimpleEJB .

SimpleEJB.java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.javacodegeeks.enterprise.ejb;
 
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
 
import com.javacodegeeks.enterprise.ejb.interceptor.SecondInterceptor;
import com.javacodegeeks.enterprise.ejb.interceptor.SimpleInterceptor;
 
@Stateless
@Interceptors({SimpleInterceptor.class, SecondInterceptor.class})
public class SimpleEJB {
 
    public String printMessage(String message) {
 
        System.out.println(" Executing method : printMessage" + message);
        return "Message is "+message;
    }
 
}

Теперь, если мы снова выдадим тот же запрос:

1
http://localhost:8080/InterceptorTesting/TestSerlvet?printMessage=Hello%20From%20JCG

Если вы посмотрите вывод Glassfish на консоли, вы увидите:

 2014-01-09T17:59:55.647+0200|INFO: Hello from Servlet 2014-01-09T17:59:55.659+0200|INFO: SimpleInterceptor - Logging BEFORE calling method :printMessage 2014-01-09T17:59:55.659+0200|INFO: SecondInterceptor - Logging BEFORE calling method :printMessage 2014-01-09T17:59:55.660+0200|INFO: Executing method : printMessageHello From JCG 2014-01-09T17:59:55.660+0200|INFO: SecondInterceptor -Logging AFTER calling method :printMessage 2014-01-09T17:59:55.660+0200|INFO: SimpleInterceptor -Logging AFTER calling method :printMessage 

9. Метод перехватчиков уровня

Иногда возможно, что вы не хотите, чтобы все ваши bean-методы были перехвачены. Вы можете выбрать, какие методы перехватывать, комментируя их, а не весь класс.

Посмотрим как:

SimpleEJB.java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.javacodegeeks.enterprise.ejb;
 
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
 
import com.javacodegeeks.enterprise.ejb.interceptor.SimpleInterceptor;
 
@Stateless
public class SimpleEJB {
 
    @Interceptors(SimpleInterceptor.class)
    public String printMessage(String message) {
 
        System.out.println(" Executing method : printMessage : " + message);
        return "Message is " + message;
    }
 
    public String printSomething(String message) {
 
        System.out.println(" Executing method : printSomething :" + message);
        return "Message is " + message;
    }
 
}

TestServlet.java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.javacodegeeks.enterprise.servlet;
 
import java.io.IOException;
 
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.javacodegeeks.enterprise.ejb.SimpleEJB;
 
@WebServlet("/TestSerlvet")
public class TestSerlvet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    public TestSerlvet() {
        super();
 
    }
 
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Hello from Servlet");
 
        InitialContext ic;
        SimpleEJB bean;
 
        String message = request.getParameter("printMessage");
 
        if (message != null) {
 
            try {
 
                ic = new InitialContext();
                bean = (SimpleEJB) ic
                        .lookup("java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB!"
                                + "com.javacodegeeks.enterprise.ejb.SimpleEJB");
 
                bean.printMessage(message);
 
                bean.printSomething("This method is not intercepted");
 
            } catch (NamingException e) {
 
                e.printStackTrace();
            }
        }
 
    }
 
}

Теперь, если мы снова выдадим тот же запрос:

1
http://localhost:8080/InterceptorTesting/TestSerlvet?printMessage=Hello%20From%20JCG

Если вы посмотрите вывод Glassfish на консоли, вы увидите:

 2014-01-09T19:52:00.909+0200|INFO: Hello from Servlet 2014-01-09T19:52:00.920+0200|INFO: SimpleInterceptor - Logging BEFORE calling method :printMessage 2014-01-09T19:52:00.921+0200|INFO: Executing method : printMessage : Hello From JCG 2014-01-09T19:52:00.921+0200|INFO: SimpleInterceptor -Logging AFTER calling method :printMessage 2014-01-09T19:52:00.921+0200|INFO: Executing method : printSomething :This method is not intercepted 

Скачать проект Eclipse

Это был пример EJB Interceptors. Загрузите Eclipse Projects этого руководства: EJBInterceptor.zip