public class CacheEJB {…}
@DependsOn содержит одну или несколько строк, каждая из которых определяет имя целевого одиночного EJB-компонента. В приведенном далее коде показано, как CacheEJB зависит от инициализации CountryCodeEJB и ZipCodeEJB. @DependsOn("CountryCodeEJB", "ZipCodeEJB") дает указание контейнеру позаботиться о том, чтобы CountryCodeEJB и ZipCodeEJB были инициализированы раньше CacheEJB.
@Singleton
public class CountryCodeEJB {…}
@Singleton
public class ZipCodeEJB {…}
@DependsOn("CountryCodeEJB", "ZipCodeEJB")
@Startup
@Singleton
public class CacheEJB {…}
Как видно в этом коде, вы даже можете комбинировать зависимости, когда речь идет об инициализации при запуске. CacheEJB быстро инициализируется при запуске (поскольку снабжен аннотацией @Startup), и, следовательно, CountryCodeEJB и ZipCodeEJB тоже будут инициализированы при запуске, но раньше CacheEJB.
Вы также можете использовать полностью уточненные имена для ссылки на одиночный EJB-объект, упакованный в другой модуль в рамках одного и того же приложения. Допустим, оба CacheEJB и CountryCodeEJB упакованы в рамках одного приложения (в один и тот же файл с расширением. ear), но в разные файлы с расширением. jar (technical.jar и business.jar соответственно). В приведенном далее коде показано, как CacheEJB зависел бы от CountryCodeEJB:
@DependsOn("business.jar#CountryCodeEJB")
@Singleton
public class CacheEJB {…}
Следует отметить, что ссылка такого рода влечет зависимость кода от деталей упаковки (которыми в данном случае являются имена файлов модулей).
Конкурентный доступ
Как вы уже понимаете, имеется единственный экземпляр одиночного сессионного EJB-компонента, который совместно используется множественными клиентами. Таким образом, конкурентный доступ для клиентов разрешается, при этом им можно управлять с помощью аннотации @ConcurrencyManagement на основе двух разных подходов.
•
•
Если не указать, на основе какого подхода должно осуществляться управление доступом, то по умолчанию будет использоваться конкурентный доступ, управляемый контейнером. В случае с одиночным EJB-компонентом может предусматриваться использование либо одного, либо другого вида доступа, но не обоих сразу. Как вы увидите в последующих разделах, аннотацию @AccessTimeout можно применять для запрета конкурентного доступа (иначе говоря, если клиент вызовет бизнес-метод, который уже используется другим клиентом, то конкурентный вызов приведет к генерированию исключения ConcurrentAccessException).
Конкурентный доступ, управляемый контейнером
При таком доступе (он является подходом по умолчанию) контейнер отвечает за управление конкурентным доступом к экземпляру одиночного EJB-компонента. Тогда вы сможете использовать аннотацию @Lock для указания того, как контейнер должен управлять доступом при вызове метода клиентом. Эта аннотация может принимать значение READ (общая блокировка) или WRITE (эксклюзивная блокировка).
• @Lock(LockType.WRITE) — метод, ассоциированный с эксклюзивной блокировкой, не позволит выполнять конкурентные вызовы до тех пор, пока не завершится обработка, осуществляемая этим методом. Например, если клиент C1 вызовет метод с эксклюзивной блокировкой, то клиент C2 не сможет вызвать этот метод, пока клиент C1 не закончит.
• @Lock(LockType.READ) — метод, ассоциированный с общей блокировкой, позволит выполнять любое количество других конкурентных вызовов для экземпляра EJB-компонента. Например, два клиента — C1 и C2 — смогут одновременно получить доступ к методу с общей блокировкой.
Аннотацией @Lock можно снабдить классы, методы либо и те и другие сразу. Если снабдить ею класс, то это будет означать, что она распространяется на все методы. Если вы не укажете атрибут блокировки конкурентного доступа, то по умолчанию будет предполагаться @Lock(WRITE). В коде, приведенном в листинге 7.11, показан CacheEJB с блокировкой WRITE в классе EJB-компонента. Это подразумевает, что для всех методов будет иметь место конкурентный доступ WRITE за исключением getFromCache(), по отношению к которому осуществляется переопределение с использованием READ.
@Singleton