CDI: использование перехватчиков в разных модулях /bean архивах
Приложение My Java EE 6 включает в себя войну и модуль ejb, упакованные в файл уха. Я использую CDI для DI (т.е. У меня есть файл beans.xml в обоих модулях). Я хочу использовать перехватчик регистрации, который также определен в модуле ejb в военном модуле. Я включил перехватчик в ejb beans.xml:
<beans>
<interceptors>
<class>com.test.interceptor.LoggingInterceptor</class>
</interceptors>
</beans>
Это работает только для классов, которые аннотируются с помощью перехватчика в модуле ejb. Классы в военном модуле не перехватываются (хотя они тоже аннотируются с перехватчиком). Я думал, что решение будет состоять в том, чтобы включить перехватчик в военном перехватчике (как и выше). Но приложение не может быть развернуто со следующим сообщением:
SEVERE: исключение при загрузке приложения: WELD-001417 Включен класс класса перехватчика com.test.interceptor.LoggingInterceptor не является аннотированным @Interceptor и не зарегистрирован через переносимое расширение
My LoggingInterceptor выглядит следующим образом:
@Log
@Interceptor
public class LoggingInterceptor {
private static final Logger logger = Logger.getLogger(LoggingInterceptor.class.getName());
static {
logger.setLevel(Level.ALL);
}
@AroundInvoke
public Object logMethod(InvocationContext ctx) throws Exception {
logger.log(Level.FINE, "ENTRY {0} {1}",
new Object[]{ ctx.getTarget().getClass().getName(), ctx.getMethod().getName() });
long startTime = System.nanoTime();
try {
return ctx.proceed();
} finally {
long diffTime = System.nanoTime() - startTime;
logger.log(Level.FINE, "RETURN {0} {1}",
new Object[]{ ctx.getTarget().getClass().getName(), ctx.getMethod().getName() });
logger.log(Level.FINE, "{0} took {1} ms", new Object[]{ ctx.getMethod(),
TimeUnit.MILLISECONDS.convert(diffTime, TimeUnit.NANOSECONDS)});
}
}
}
И привязка перехватчика:
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Log {}
Как я могу использовать перехватчик для обоих модулей?
Ответы
Ответ 1
Спецификация J2EE 7 говорит (ссылка):
Перехватчики, указанные вами в файле beans.xml, применяются только к классы в том же архиве. Используйте аннотацию @Priority, чтобы указать перехватчиков по всему миру для приложения, которое состоит из нескольких Модули
Это решение имеет то преимущество, что оно не зависит от поставщика.
Пример:
@Logged
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
Ответ 2
Слишком поздно, но если у кого-то все еще есть эта проблема.
Оба модуля должны загружаться одним и тем же загрузчиком классов, чтобы можно было использовать перехватчик по разным модулям, по крайней мере, в WebSphere 8b2.
В WebSphere этот параметр можно переключить в консоли администрирования: Приложения > Типы приложений > Корпоративные приложения WebSphere > [имя вашего приложения] > Обнаружение загрузки и обнаружение классa > Политика загрузчика WAR-класса = Одиночный загрузчик классов для приложения.
Перехватчик должен быть включен только ONCE в beans.xml.
Ответ 3
Интересно, не испытывает ли ваша WAR недостаток classloader в вашей ejb-jar? Я думаю, что в идеале 299-перехватчики будут находиться в их собственной банке, видимой как для EJB, так и для веб-модулей и включаться в оба их beans.xml.
Ответ 4
У меня такая же проблема в JBoss AS 6.0/6.1 (ночная сборка) и исправлена с помощью отключение отдельных загрузчиков классов (вариант 1), но будьте предельно осторожны с этим. Разделение загрузчиков классов не было введено ни по какой причине, поэтому, по-видимому, на дороге есть новые проблемы...
Это - отчет о джире, пожалуйста, проголосуйте за него: -)
Ответ 5
У меня была точно такая же проблема с моим протоколированием перехватчика на JBoss 7 и исправлена его, наложив полный баннер перехватчика на приложение.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<overlays>
<overlay>
<groupId>com.github.t1</groupId>
<artifactId>logging-interceptor</artifactId>
<type>jar</type>
<targetPath>WEB-INF/classes</targetPath>
</overlay>
</overlays>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.github.t1</groupId>
<artifactId>logging-interceptor</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
</dependencies>
Вам все равно придется активировать перехватчик в приложении breans.xml
.
Не нравится, но он работает. В Java EE 7 он работает без активации, аннотируя перехватчик как @Priority
.
Ответ 6
Если у вас нет контроля над внешней зависимостью и вы все еще хотите включить перехватчики без beans.xml, вы можете написать расширение CDI:
package my.package;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterTypeDiscovery;
import javax.enterprise.inject.spi.Extension;
public class MyCdiExtension implements Extension {
public void observeAfterTypeDiscovery(@Observes AfterTypeDiscovery afterTypeDiscovery) {
afterTypeDiscovery.getInterceptors().add(SomeExternalInterceptor.class);
}
}
Добавить файл resources/META-INF/services/javax.enterprise.inject.spi.Extension
с содержанием:
my.package.MyCdiExtension