@Alternative
@ThirteenDigits
public class MockGenerator implements NumberGenerator {
··@Inject
··private Logger logger;
··@Loggable
··public String generateNumber() {
····String mock = "MOCK-" + Math.abs(new Random(). nextInt());
····logger.info("Сгенерирован Mock: " + mock);
····return mock;
··}
}
Написание квалификаторов
Поскольку существует несколько реализаций NumberGenerator, CDI необходимо квалифицировать каждый компонент и каждую точку внедрения во избежание неоднозначного внедрения. Для этого он использует два квалификатора: Thirteen Digits (листинг 2.46) и EightDigits (листинг 2.47), оба из которых аннотированы javax.inject.Qualifier и не имеют членов (просто пустые аннотации). Аннотация @ThirteenDigits применяется в компоненте IsbnGenerator (см. листинг 2.43), а также в точке внедрения BookService (см. листинг 2.40).
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface ThirteenDigits { }
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface EightDigits { }
Написание автоматического журнала
Демонстрационное приложение использует запись в журнал несколькими способами. Как вы могли видеть в листингах 2.43–2.45, все реализации NumberGenerator применяют внедрение для получения java.util.logging.Logger и записи в журнал. Поскольку Logger входит в состав JDK, он не является внедряемым по умолчанию (архив rt.jar не содержит файла beans.xml) и вам необходимо произвести его. Класс LoggingProducer в листинге 2.48 имеет метод продюсера (produceLogger), аннотированный @Produces. Этот метод создаст и вернет Logger, сопровождаемый параметрами имени класса точки внедрения.
public class LoggingProducer {
··@Produces
··public Logger produceLogger(InjectionPoint injectionPoint) {
····return Logger.getLogger(injectionPoint.getMember(). getDeclaringClass(). getName());
··}
}
Класс LoggingInterceptor в листинге 2.49 использует произведенный Logger для регистрации входа в методы и выхода из них. Поскольку запись в журнал может рассматриваться как сквозная функциональность, она отдельно реализуется в виде перехватчика (@AroundInvoke на logMethod). Класс LoggingInterceptor определяет связь с перехватчиком @Loggable (листинг 2.50) и может впоследствии применяться в любом компоненте (например, BookService в листинге 2.40).
@Interceptor
@Loggable
public class LoggingInterceptor {
··@Inject
··private Logger logger;
··@AroundInvoke
··public Object logMethod(InvocationContext ic) throws Exception {
····logger.entering(ic.getTarget(). getClass(). getName(),
ic.getMethod(). getName());
····try {
······return ic.proceed();
····} finally {
······logger.exiting(ic.getTarget(). getClass(). getName(),
ic.getMethod(). getName());
····}
··}
}
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Loggable { }
Написание класса Main