Еще один ранний выпуск модуля Spring-CDI, на этот раз это реализация шаблона перехватчика. Он реализует JSR-299-совместимую модель привязки перехватчиков для управляемых компонентов Spring. Мы будем использовать это в наших бизнес-приложениях для сквозных задач.
Реализация шаблона перехватчика JSR-299
Характеристики
Модуль перехватчика обеспечивает следующие функции:
- Используйте аннотации JSR-299 @Interceptor, @InterceptorBinding, @AroundInvoke и @Nonbinding и их определенную семантику в управляемых компонентах Spring
- Поддержка перехватчиков на уровне класса (применяется ко всем объявленным методам), а также на определенных методах (перехватчики уровня метода)
- Поддержка цепочек из нескольких перехватчиков для одного и того же целевого метода
- Поддержка целевых бобов
- Интеграция с Spring AOP (только прокси CGLIB)
Перехватчики для обратных вызовов событий жизненного цикла поддерживаются начиная с Spring 2.5 и поэтому не являются предметом этого модуля Sping-CDI (аннотации @PostConstruct и @PreDestroy).
Этот выпуск модуля перехватчика Spring-CDI не поддерживает аннотацию JSR318 @Interceptors. Спецификация CDI гласит: «Если перехватчик не объявляет аннотацию @Interceptor, он должен быть связан с bean-компонентами, использующими @Interceptors или ejbjar.xml.» Поскольку JSR299 определяет @InterceptorBinding в качестве механизма привязки, я бы не рекомендовал больше использовать аннотацию @Interceptors.
Перехватчики тайм-аута и перехватчики по умолчанию пока не поддерживаются.
Ссылка на скачивание
Модуль перехватчика Spring-CDI — это обычное расширение IoC-контейнера Spring, поставляемое в виде архива JAR. Вы можете скачать модуль JAR и поместить его в путь к классу вашего приложения Spring.
Скомпилированный модуль перехватчика Spring-CDI JAR: версия 0.5.1
Источники: Версия 0.5.1
API-Doc: Версия 0.5.1
Все размещено в git-репозитории на Github.com .
зависимости
Вот мои зависимости во время выполнения:
<dependency> <groupid>org.springframework</groupid> <artifactid>spring-context</artifactid> <version>${spring.version}</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>org.springframework.aop</artifactid> <version>${spring.version}</version> </dependency> <dependency> <groupid>javax.enterprise</groupid> <artifactid>cdi-api</artifactid> <version>1.0</version> </dependency> <dependency> <groupid>org.jboss.spec.javax.interceptor</groupid> <artifactid>jboss-interceptors-api_1.1_spec</artifactid> <version>1.0.0.Final</version> </dependency> <dependency> <groupid>cglib</groupid> <artifactid>cglib</artifactid> <version>2.2.2</version> </dependency>
Конфигурация
Если JAR-модуль перехватчика Spring-CDI и его зависимости находятся на вашем пути к классам, все, что вам нужно сделать, это:
(1) зарегистрировать InterceptorAwareBeanFactoryPostProcessor в контексте вашего приложения
(2) определить фильтр включения, чтобы включить javax.interceptor.Interceptor в качестве компонента аннотация в вашем контексте: тег компонентного сканирования
<beans> ... <context:component-scan base-package="com.schlimm.springcdi.interceptor.simple" scoped-proxy="targetClass"> <context:include-filter type="annotation" expression="javax.interceptor.Interceptor" /> </context:component-scan> <bean class="com.schlimm.springcdi.interceptor.InterceptorAwareBeanFactoryPostProcessor"/> ... </beans>
Если вы хотите заказать перехватчики, вам нужно настроить свойство interceptorOrder для InterceptorAwareBeanFactoryPostProcessor:
<bean class="com.schlimm.springcdi.interceptor.InterceptorAwareBeanFactoryPostProcessor"> <property name="interceptorOrder"> <list> <value>com.schlimm.springcdi.interceptor.ct._91_C1.interceptors.TransactionInterceptor</value> <value>com.schlimm.springcdi.interceptor.ct._92_C1.interceptors.OldSecurityInterceptor</value> <value>com.schlimm.springcdi.interceptor.ct._92_C1.interceptors.VIPSecurityInterceptor</value> <value>com.schlimm.springcdi.interceptor.ct._92_C1.interceptors.SecurityInterceptor</value> </list> </property> </bean>
Пример использования
В следующих фрагментах кода показано, как можно использовать шаблоны перехватчиков, которые вы настроили в приложении Spring, как описано выше. Для более сложных сценариев смотрите мои примеры модульных тестов.
Предположим, у вас есть бизнес-интерфейс с именем: Simple_MyServiceInterface
public interface Simple_MyServiceInterface { String sayHello(); String sayHello(String what); String sayGoodBye(); }
Это ваша реализация сервиса.
@Component @ReturnValueAdopted public class Simple_MyServiceInterface_Impl implements Simple_MyServiceInterface { @Override public String sayHello() { return "Hello"; } @Override public String sayHello(String what) { return what; } @Override public String sayGoodBye() { return "Good bye"; } }
Обратите внимание на аннотацию @ReturnValueAdopted на уровне типа. Это объявление привязки перехватчика:
@Inherited @InterceptorBinding @Target({TYPE, METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ReturnValueAdopted { }
Этот перехватчик также объявляет привязку перехватчика @ReturnValueAdopted, что означает, что перехватчик применяется к Simple_MyServiceInterface_Impl.
@Interceptor @ReturnValueAdopted public class Simple_MyInterceptor { @AroundInvoke public String extendReturnValueWithSomeNonsense(InvocationContext ctx) throws Exception { String result = null; ctx.getContextData().put("Some", "Nonsense"); try { result = (String)ctx.proceed(); } catch (Exception e) { throw new RuntimeException(e); } return result + "_hello_world"; } }
Аннотация @Interceptor объявляет класс как перехватчик. Он будет перехватывать все вызовы методов в бине Simple_MyServiceInterface_Impl. Более конкретно, он расширит возвращаемые значения с помощью «_hello_world» Также обратите внимание на данные контекста, записанные в InvocationContext. Это позволяет цепям перехватчиков обмениваться контекстными данными.
Теперь вы можете автоматически связать bean-компонент Simple_MyServiceInterface_Impl в произвольные bean-компоненты:
@ContextConfiguration("/test-context-interceptor-simple.xml") @RunWith(SpringJUnit4ClassRunner.class) @DirtiesContext public class SimpleInterceptorTestCase { @Autowired // will be intercepted private Simple_MyServiceInterface someInterceptedBean; @Test public void testHelloWorldExtension() { Assert.assertTrue(someInterceptedBean.sayHello().equals("Hello_hello_world")); } }
Для внедренного компонента будет применен определенный Simple_MyInterceptor. Когда вызывается метод sayHello (), перехватчик расширяет возвращаемое значение сообщением «_hello_world».
Как это работает
Основой является InterceptorAwareBeanFactoryPostProcessor . Он использует две стратегии для реализации логики. InterceptorResolutionLogic сканирует контекст приложения на наличие зарегистрированных перехватчиков. InterceptorOrderingStrategy реализует порядок цепочек перехватчиков для вызова целевого метода. Результат сбора данных в рамках этих двух стратегий сохраняется в InterceptorMetaDataBean. Постпроцессор фабрики бинов также регистрирует InterceptorAwareBeanPostProcessorwith создает прокси для каждого перехваченного компонента. Этот прокси-сервер имеет перехваченный компонент в качестве цели и InterceptedBeanProxyAdvice в качестве рекомендации перехватчика. Этот совет создает (и кэширует) цепочки пользовательских перехватчиков JSR299 для каждого уникального вызова метода. Он извлекает необходимые метаданные для цепочки перехватчиков из InterceptorMetaDataBean.
Попробуйте все, если у вас есть время!
От http://niklasschlimm.blogspot.com/2011/08/jsr-299-cdi-interceptors-for-spring.html