В этом посте объясняется (на простом примере), как вы можете использовать производителей CDI, чтобы немного упростить использование семантики управления кэшем в ваших сервисах RESTful.
Заголовок Cache-Control был добавлен в HTTP 1.1 как очень необходимое улучшение по сравнению с заголовком Expires, доступным в HTTP 1.0. Веб-сервисы RESTful могут использовать этот заголовок для масштабирования своих приложений и повышения их эффективности, например, если вы можете кэшировать ответ на предыдущий запрос, то вам, очевидно, нет необходимости повторять тот же запрос к серверу, если вы уверены в тот факт, что ваши кэшированные данные не устарели!
Как помогает JAX-RS?
JAX-RS поддерживает заголовок Cache-Control начиная с его начальной версии (1.0). Класс CacheControl представляет реальный HTTP-заголовок Cache-Control и предоставляет возможность конфигурировать заголовок с помощью простых методов установки. Подробнее о классе CacheControl в javadocs JAX-RS 2.0
Так как же использовать класс CacheControl ?
Просто верните объект Response, вокруг которого вы можете обернуть экземпляр класса CacheControl.
|
01
02
03
04
05
06
07
08
09
10
|
@Path("/testcache")public class RESTfulResource { @GET @Produces("text/plain") public Response find(){ CacheControl cc = new CacheControl(); cc.setMaxAge(20); return Response.ok(UUID.randomUUID().toString()).cacheControl(cc).build(); }} |
Хотя это относительно удобно для одного метода, повторное создание и возврат объектов CacheControl может вызывать раздражение для нескольких методов.
Производители CDI на помощь!
Производители CDI могут помочь внедрить экземпляры классов, которые технически не являются bean-компонентами (согласно строгому определению) или для классов, над которыми у вас нет контроля, если их украшать областями видимости и определителями.
Идея состоит в том, чтобы
- Используйте пользовательскую аннотацию ( @CacheControlConfig ) для определения значений по умолчанию для заголовка Cache-Control и обеспечения гибкости в случае, если вы хотите переопределить его
0102030405060708091011121314
@Retention(RUNTIME)@Target({FIELD, PARAMETER})public@interfaceCachControlConfig {publicbooleanisPrivate()defaulttrue;publicbooleannoCache()defaultfalse;publicbooleannoStore()defaultfalse;publicbooleannoTransform()defaulttrue;publicbooleanmustRevalidate()defaulttrue;publicbooleanproxyRevalidate()defaultfalse;publicintmaxAge()default0;publicintsMaxAge()default0;} - Просто используйте CDI Producer для создания экземпляра класса CacheControl с помощью объекта InjectionPoint (с удовольствием вводится CDI!) В зависимости от параметров аннотации
01020304050607080910111213141516171819202122
publicclassCacheControlFactory {@ProducespublicCacheControl get(InjectionPoint ip) {CachControlConfig ccConfig = ip.getAnnotated().getAnnotation(CachControlConfig.class);CacheControl cc =null;if(ccConfig !=null) {cc =newCacheControl();cc.setMaxAge(ccConfig.maxAge());cc.setMustRevalidate(ccConfig.mustRevalidate());cc.setNoCache(ccConfig.noCache());cc.setNoStore(ccConfig.noStore());cc.setNoTransform(ccConfig.noTransform());cc.setPrivate(ccConfig.isPrivate());cc.setProxyRevalidate(ccConfig.proxyRevalidate());cc.setSMaxAge(ccConfig.sMaxAge());}returncc;}} - Просто внедрите экземпляр CacheControl в свой класс ресурсов REST и используйте его в своих методах
010203040506070809101112
@Path("/testcache")publicclassRESTfulResource {@Inject@CachControlConfig(maxAge =20)CacheControl cc;@GET@Produces("text/plain")publicResponse find() {returnResponse.ok(UUID.randomUUID().toString()).cacheControl(cc).build();}}
Дополнительные мысли
- В этом случае область действия созданного экземпляра CacheControl равна @Dependent, т.е. он будет жить и умирать с классом, который его внедрил . В этом случае сам ресурс JAX-RS является RequestScoped (по умолчанию), поскольку контейнер JAX-RS создает новый экземпляр для каждого клиентского запроса, следовательно, новый экземпляр внедренного экземпляра CacheControl будет создаваться вместе с каждым HTTP-запросом.
- Вы также можете ввести классификаторы CDI для дальнейшего сужения областей и учета угловых случаев.
- Вы можете подумать, что того же можно достичь с помощью фильтра JAX-RS. Это правильно. Но вам нужно будет установить заголовок Cache-Control вручную (в изменяемой переменной MultivaluedMap), и логика не будет достаточно гибкой, чтобы учитывать различные конфигурации Cache-Control для разных сценариев
Результаты эксперимента
Используйте среду IDE NetBeans, чтобы поиграть с этим примером (рекомендуется)
- Разверните WAR и перейдите по адресу http: // localhost: 8080 / JAX-RS-Caching-CDI / testcache
- Случайная строка, которая будет кэшироваться в течение 20 секунд (согласно конфигурации с помощью аннотации @CacheControl)
- Запрос GET на тот же URL не приведет к вызову службы REST на стороне сервера. Браузер вернет кэшированное значение.
Хотя код прост, но если вам лень, вы можете взять отсюда (maven) проект и поиграть
Повеселись!
| Ссылка: | Упрощение кэширования JAX-RS с помощью CDI от нашего партнера JCG Абхишека Гупты в блоге Object Oriented .. |


