Главная » Spring » Создание  «осведомленных» компонентов Spring

0

Вы видели фильм «Матрица»? В этом фильме люди были неволь- но порабощены машинами, жили своими каждодневными жизнями в виртуальном мире, в то время как суть их жизни состояла в том, чтобы обеспечить машины энергией. Главному персонажу Томасу Андерсону (Thomas Anderson) был дан выбор – принять красную пилюлю и узнать всю правду о своем существовании или принять синюю пилюлю и продолжить прежнюю жизнь. Он выбрал красную и сделался осведомленным о своей реальной личности и о виртуаль- ном мире.

Большая часть компонентов, выполняющихся в контейнере Spring, подобны людям в фильме «Матрица». Для компонентов не- знание есть счастье. Они (компоненты) не знают (им даже не по- ложено знать) свои имена или что они действуют внутри контейнера Spring. Как правило, это хорошо, потому что когда компонент знает о контейнере, его связь со Spring усиливается, и он уже не сможет существовать вне контейнера.

Но иногда компонентам надо знать больше. Иногда им надо знать, кто они есть и где они действуют. Иногда им необходимо взять крас- ную пилюлю.

Красная пилюля в случае с компонентами – это интерфейсы NameAware, BeanFactoryAware и ApplicationContextAware. Реализуя эти три интерфейса, компоненты будут знать свое имя и свой контейнер – BeanFactory  или ApplicationContext  соответственно.

Но имейте в виду, что, реализуя эти интерфейсы, компоненты ста- новятся связанными со Spring. И в зависимости от того, как ком- понент использует это знание, у вас может не быть возможности использовать его вне Spring.

Кто ты есть

Контейнер Spring сообщает компоненту о его имени через интер- фейс BeanNameAware. Этот интерфейс определяет единственный метод setBeanName(), который получает строку с именем компонента, указан- ную в атрибуте id элемента <bean> в файле с настройками компонентов:

public interface BeanNameAware { void setBeanName(String name);

}

Знание своего имени может пригодиться компоненту для ведения учета. Например, компонент может существовать в контексте при- ложения в нескольких экземплярах, и возможность самоидентифи- кации по имени и типу для регистрации в журнале собственных действий может оказаться весьма кстати.

Внутри самого фреймворка Spring Framework интерфейс BeanName- Aware используется в разных целях. Наиболее известным примером могут служить компоненты, выполняющие функции планирования. Например, CronTriggerBean, реализующий интерфейс BeanNameAware для установки имени своего задания CronTrigger. Это иллюстрирует сле- дующий отрывок из CronTriggerBean:

package  org.springframework.scheduling.quartz; public class CronTriggerBean extends CronTrigger

implements    …,    BeanNameAware,    …     {

private String beanName;

public  void  setBeanName(String  beanName)  { this.beanName = beanName;

}

public  void  afterPropertiesSet()  …   { if  (getName()  ==   null){

setBeanName(this.beanName);

}

}

}

Не требуется ничего особенного, чтобы контейнер Spring вызвал метод setBeanName() в классе, реализующем интерфейс BeanNameAware. Во время загрузки компонента контейнер обнаружит, что компонент реализует интерфейс BeanNameAware, и автоматически вызовет метод setBeanName(), передав ему имя компонента, объявленное в атрибуте id (либо name) элемента <bean> в XML-файле конфигурации компо- нентов.

Здесь класс CronTriggerBean расширяет класс CronTrigger. После то- го как контекст Spring установит значения всех свойств компонен- та, он вызовет метод setBeanName() (объявленный в CronTriggerBean) и передаст ему имя компонента, которое будет использоваться для установки имени планируемого задания.

Этот пример иллюстрирует использование интерфейса BeanName- Aware на примере встроенного в Spring планировщика. Подробнее о планировании будет рассказано в главе 17. А пока посмотрим, как наделить компонент знанием о контейнере Spring, внутри которого он действует.

Где ты живешь

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

Получить информацию о контейнере компоненту помогут ин- терфейсы ApplicationContextAware и BeanFactoryAware. Эти интерфейсы объявляют методы setApplicationContext() и setBeanFactory() соответ- ственно. Контейнер Spring автоматически обнаруживает компонен- ты, реализующие любой из этих интерфейсов, и обеспечит передачу компоненту ссылки на соответствующий контейнер.

Имея доступ к контексту приложения ApplicationContext, компонент может активно взаимодействовать с контейнером. Это может приго- диться для программного поиска зависимостей в контейнере (если они не были внедрены самим контейнером) или для публикации со- бытий в приложении. Возвращаясь к примеру публикации событий, приведенному выше, можно завершить его, как показано ниже:

public  class  StudentServiceImpl

implements  StudentService,  ApplicationContextAware  {

private ApplicationContext context;

public  void  setApplicationContext(ApplicationContext  context)  { this.context   =   context;

}

public  void  enrollStudentInCourse(Course  course,  Student  student) throws  CourseException;

}

}

context.publishEvent(new CourseFullEvent(this, course));

Осведомленность о контейнере приложения – одновременно и благо, и проклятие для компонента. С одной стороны, доступ к кон- тексту приложения расширяет возможности компонента, с другой стороны – знание о контейнере связывает компонент с фреймвор- ком Spring, а это то, чего, в принципе, желательно избегать, по воз- можности.

До сих пор предполагалось, что все компоненты в контейнере Spring реализованы как Java-классы. Это вполне обоснованное пред- положение, но совершенно необязательное. Посмотрим далее, как добавить в приложение динамическое поведение, включая в него компоненты, реализованные с использованием языков сценариев.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии