В большинстве примеров в этой главе для указания конфигурационных метаданных, которые создают каждое BeanDefinition
в контейнере Spring, используется XML. В предыдущем разделе показано, как предоставить большую часть конфигурационных метаданных через аннотации на уровне источника. Однако даже в этих примерах определения "базовых" бинов явно определены в XML-файле, а аннотации определяют только внедрение зависимостей. В этом разделе описывается возможность неявного обнаружения компонентов-кандидатов путем сканирования classpath. Компоненты-кандидаты – это классы, которые соответствуют критериям фильтра и имеют соответствующее определение бина, зарегистрированное в контейнере. Это устраняет необходимость использования XML для выполнения регистрации бина. Вместо этого вы можете использовать аннотации (например, @Component
), выражения типов AspectJ или собственные кастомные критерии фильтрации, чтобы выбрать, какие классы имеют определения бина, зарегистрированные в контейнере.
Начиная со Spring 3.0, многие функции, предоставляемые проектом Spring JavaConfig, являются частью основной платформы Spring Framework. Это позволяет вам определять бины с помощью Java, а не с помощью традиционных XML-файлов. Взгляните на аннотации @Configuration
, @Bean
, @Import
и @DependsOn
как примеры использования этих новых возможностей.
@Component
и дополнительные стереотипные аннотации
Аннотация @Repository
– это маркер для любого класса, который исполняет роль или стереотип репозитория (также известного как объект доступа к данным или DAO). Среди способов использования этого маркера - автоматическое преобразование исключений.
Spring предоставляет дополнительные стереотипные аннотации: @Component
, @Service
и @Controller
. @Component
– это общий стереотип для любого компонента, управляемого Spring. @Repository
, @Service
и @Controller
– это специализированные формы @Component
для более конкретных случаев использования (на уровнях хранения, сервисном и представления, соответственно). Поэтому вы можете аннотировать свои компонентные классы с помощью @Component
, но, если вместо этого аннотировать их @Repository
, @Service
или @Controller
, ваши классы будут больше подходить для обработки инструментами или связи с аспектами. Например, эти стереотипные аннотации являются идеальными целями для срезов. @Repository
, @Service
и @Controller
также могут нести дополнительную семантику в будущих выпусках Spring Framework. Таким образом, если вы делаете выбор между @Component
и @Service
для вашего сервисного уровня, @Service
будет явно лучшим выбором. Аналогично, как было отмечено ранее, @Repository
уже поддерживается как маркер для автоматического преобразования исключений на вашем уровне хранения.
Использование мета-аннотаций и составных аннотаций
Многие из аннотаций, предоставляемых Spring, могут быть использованы в качестве мета-аннотаций в вашем собственном коде. Мета-аннотация – это аннотация, которая может быть применена к другой аннотации. Например, аннотация @Service
, упомянутая ранее, мета-аннотируется с помощью @Component
, как показано в следующем примере:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
// ...
}
- Аннотация
@Component
делает так, что аннотация@Service
обрабатывается так же, как и@Component
.
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
annotation class Service {
// ...
}
- Аннотация
@Component
делает так, что аннотация@Service
обрабатывается так же, как и@Component
.
Вы также можете комбинировать мета-аннотации для создания "составных аннотаций". Например, аннотация @RestController
из Spring MVC состоит из @Controller
и @ResponseBody
.
Кроме того, составные аннотации могут по необходимости повторно объявлять атрибуты из мета-аннотаций для обеспечения возможности настройки. Это может быть особенно полезно, если нужно открыть только часть атрибутов мета-аннотации. Например, аннотация @SessionScope
в Spring жестко кодирует имя области доступности как session
, но при этом позволяет настраивать proxyMode
. В следующем листинге показано определение аннотации SessionScope
:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {
/**
* Псевдоним для {@link Scope#proxyMode}.
* <p>По умолчение имеет значение {@link ScopedProxyMode#TARGET_CLASS}.
*/
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Scope(WebApplicationContext.SCOPE_SESSION)
annotation class SessionScope(
@get:AliasFor(annotation = Scope::class)
val proxyMode: ScopedProxyMode = ScopedProxyMode.TARGET_CLASS
)
Затем можно использовать @SessionScope
без объявления proxyMode
следующим образом:
@Service
@SessionScope
public class SessionScopedService {
// ...
}
@Service
@SessionScope
class SessionScopedService {
// ...
}
Также можно переопределить значение для proxyMode
, как показано в следующем примере:
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
// ...
}
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
class SessionScopedUserService : UserService {
// ...
}
Более подробную информацию можно найти на вики-странице Spring Annotation Programming Model.
Автоматическое обнаружение классов и регистрация определений бинов
Spring может автоматически обнаруживать стереотипизированные классы и регистрировать соответствующие экземпляры BeanDefinition
в ApplicationContext
. Например, следующие два класса могут быть автоматически обнаружены:
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
@Service
class SimpleMovieLister(private val movieFinder: MovieFinder)
@Repository
public class JpaMovieFinder implements MovieFinder {
// реализация опущена для ясности
}
@Repository
class JpaMovieFinder : MovieFinder {
// реализация опущена для ясности
}
Для автоматического обнаружения этих классов и регистрации соответствующих бинов необходимо добавить @ComponentScan
в класс @Configuration
, где атрибут basePackages
является общим родительским пакетом для двух классов. (Как вариант, можно указать список, разделенный запятыми, точкой с запятой или пробелами, который включает родительский пакет каждого класса).
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"])
class AppConfig {
// ...
}
value
аннотации (то есть @ComponentScan("org.example")
).В следующей альтернативе используется XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example"/>
</beans>
<context:component-scan>
неявно активирует функциональность <context:annotation-config>
. Обычно нет необходимости включать элемент <context:annotation-config>
при использовании <context:component-scan>
.Сканирование пакетов classpath требует наличия соответствующих записей каталога в classpath. Если вы собираете JAR с помощью Ant, убедитесь, что не активируете переключатель "только файлы" в задаче JAR. Кроме того, каталоги пути классов могут быть закрыты на основании политик безопасности в некоторых средах – например, автономные приложения на JDK 1.7.0_45 и выше (что требует установки доверяемой библиотеки ('Trusted-Library') в ваших манифестах - см. https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources).
По пути модулей JDK 9 (Jigsaw) сканирование classpath Spring в целом работает так, как ожидается. Однако убедитесь, что классы ваших компонентов экспортированы в дескрипторы module-info
. Если вы ожидаете, что Spring будет вызывать непубличные члены ваших классов, убедитесь, что они 'открыты' (то есть, что они используют объявление opens
вместо объявления exports
в вашем дескрипторе module-info
).
Более того, AutowiredAnnotationBeanPostProcessor
и CommonAnnotationBeanPostProcessor
неявно включаются при использовании элемента component-scan. Это означает, что два компонента автоматически обнаруживаются и соединяются вместе - и все это без каких-либо конфигурационных метаданных бина, указанных на XML.
AutowiredAnnotationBeanPostProcessor
и CommonAnnotationBeanPostProcessor
, включив атрибут annotation-config
со значением false
.Использование фильтров для настройки сканирования
По умолчанию классы, аннотированные @Component
, @Repository
, @Service
, @Controller
, @Configuration
или кастомной аннотацией, которая сама аннотирована @Component
, являются единственными компонентами-кандидатами для обнаружения. Однако вы можете изменять и расширять эту логику работы, применяя кастомные фильтры. Добавьте их как атрибуты includeFilters
или excludeFilters
аннотации @ComponentScan
(или как дочерние элементы <context:include-filter />
или <context:exclude-filter />
элемента <context:component-scan>
в конфигурации XML). Каждый элемент фильтра требует наличия атрибутов type
и expression
. В следующей таблице описаны параметры фильтрации:
Тип фильтра | Пример выражения | Описание |
---|---|---|
annotation (по умолчанию) |
|
Аннотация, которая должна быть present или meta-present на уровне типа в целевых компонентах. |
assignable |
|
Класс (или интерфейс), на который могут быть назначены (расширены или реализованы) целевые компоненты. |
aspectj |
|
Выражение типа AspectJ, которому должны соответствовать целевые компоненты. |
regex |
|
Регулярное выражение для сопоставления с именами классов целевых компонентов. |
custom |
|
Кастомная реализация интерфейса |
В следующем примере показана конфигурация, игнорирующая все аннотации @Repository
и использующая вместо них репозитории с "функцией-заглушкой":
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"],
includeFilters = [Filter(type = FilterType.REGEX, pattern = [".*Stub.*Repository"])],
excludeFilters = [Filter(Repository::class)])
class AppConfig {
// ...
}
В следующем листинге показан эквивалент на XML:
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex"
expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
useDefaultFilters=false
в аннотации или предоставив use-default-filters="false"
в качестве атрибута элемента <component-scan/>
. Таким способом можно эффективно отключить автоматическое обнаружение классов, аннотированных или мета-аннотированных @Component
, @Repository
, @Service
, @Controller
, @RestController
или @Configuration
.Определение метаданных бинов в компонентах
Компоненты Spring могут также вносить метаданные определения бинов в контейнер. Это можно сделать с помощью той же аннотации @Bean
, которая используется для определения метаданных бина в классах, помеченных аннотацией @Configuration
. В следующем примере показано, как это сделать:
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Реализация метода компонента опущена
}
}
@Component
class FactoryMethodComponent {
@Bean
@Qualifier("public")
fun publicInstance() = TestBean("publicInstance")
fun doWork() {
// Реализация метода компонента опущена
}
}
Предыдущий класс является компонентом Spring, который имеет специфичный для приложения код в методе doWork()
. Однако он также вносит определение бина, которое имеет фабричный метод, ссылающийся на метод publicInstance()
. Аннотация @Bean
идентифицирует фабричный метод и другие свойства определения бина, такие как значение квалификатора через аннотацию @Qualifier
. Другие аннотации уровня метода, которые могут быть заданы, это @Scope
, @Lazy
и аннотации кастомных квалификаторов.
@Lazy
на точки внедрения, помеченные @Autowired
или @Inject
. В данном контексте это приводит к внедрению прокси с отложенным разрешением. Однако такой подход с задействованием прокси довольно ограничен. Вместо него для сложных отложенных взаимодействий, в частности, в сочетании с необязательными зависимостями, мы рекомендуем ObjectProvider<MyTargetBean>
.Поддерживаются автоматически обнаруженные и связанные поля и методы, как было упомянуто ранее, с дополнительной поддержкой автоматического обнаружения и связывания методов @Bean
. В следующем примере показано, как это сделать:
@Component
public class FactoryMethodComponent {
private static int i;
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
// использование пользовательского квалификатора и автоматического обнаружения и связывания параметров метода
@Bean
protected TestBean protectedInstance(
@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(spouse);
tb.setCountry(country);
return tb;
}
@Bean
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean
@RequestScope
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
@Component
class FactoryMethodComponent {
companion object {
private var i: Int = 0
}
@Bean
@Qualifier("public")
fun publicInstance() = TestBean("publicInstance")
// использование пользовательского квалификатора и автоматического обнаружения и связывания параметров метода
@Bean
protected fun protectedInstance(
@Qualifier("public") spouse: TestBean,
@Value("#{privateInstance.age}") country: String) = TestBean("protectedInstance", 1).apply {
this.spouse = spouse
this.country = country
}
@Bean
private fun privateInstance() = TestBean("privateInstance", i++)
@Bean
@RequestScope
fun requestScopedInstance() = TestBean("requestScopedInstance", 3)
}
В примере выполняется автоматическое обнаружение и связывание String
параметра метода country
со значением свойства age
другого бина с именем privateInstance
. Элемент языка выражений Spring Expression Language определяет значение свойства через обозначение #{ <expression> }
. Для аннотаций @Value
распознаватель выражений предварительно настроен на поиск имен бинов при разрешении текста выражения.
Начиная с версии Spring Framework 4.3, вы также можете объявить параметр фабричного метода типа InjectionPoint
(или его более конкретного подкласса: DependencyDescriptor
) для получения доступа к точке внедрения запроса, которая вызывает создание текущего бина. Обратите внимание, что это касается только фактического создания экземпляров бина, а не внедрения существующих экземпляров. Как следствие, эта функция имеет смысл для бинов, находящихся в области доступности prototype. Для других областей доступности фабричный метод распознает только точку внедрения, которая вызвала создание нового экземпляра бина в данной области доступности (например, зависимость, которая вызвала создание бина-одиночки с отложенной инициализацией). В таких сценариях можно использовать предоставленные метаданные точки внедрения с соблюдением семантической осторожности. В следующем примере показано, как использовать InjectionPoint
:
@Component
public class FactoryMethodComponent {
@Bean @Scope("prototype")
public TestBean prototypeInstance(InjectionPoint injectionPoint) {
return new TestBean("prototypeInstance for " + injectionPoint.getMember());
}
}
@Component
class FactoryMethodComponent {
@Bean
@Scope("prototype")
fun prototypeInstance(injectionPoint: InjectionPoint) =
TestBean("prototypeInstance for ${injectionPoint.member}")
}
Методы с аннотацией @Bean
в обычном компоненте Spring обрабатываются иначе, чем их аналоги в классе с аннотацией@Configuration
в Spring. Разница состоит в том, что классы @Component
нельзя расширить с помощью CGLIB для перехвата вызовов методов и полей. CGLIB-проксирование – это средство, с помощью которого вызов методов или полей внутри методов, помеченных аннотацией @Bean
, в классах с аннотацией @Configuration
создает ссылки метаданных бина на взаимодействующие объекты. Такие методы не вызываются с использованием типовой семантики Java, а проходят через контейнер, чтобы обеспечить привычное управление жизненным циклом и проксирование бинов в Spring, даже при обращении к другим бинам через программные вызовы методов @Bean
. В отличие от этого, вызов метода или поля в методе @Bean
в обычном классе @Component
имеет стандартную семантику Java, без специальной обработки CGLIB или других ограничений.
Вы можете объявить методы, аннотированные @Bean
, как статические, что позволит вызывать их без создания содержащего их конфигурационного класса в качестве экземпляра. Это имеет особый смысл при определении бинов постпроцессора (например, типа BeanFactoryPostProcessor
или BeanPostProcessor
), поскольку такие бины инициализируются на ранней стадии жизненного цикла контейнера и должны избегать запуска других частей конфигурации в этот момент.
Вызовы статических методов @Bean
никогда не перехватываются контейнером, даже внутри классов @Configuration
(как описано ранее в этом разделе), из-за технических ограничений: Подклассы CGLIB могут переопределять только нестатические методы. Как следствие, прямой вызов другого метода @Bean
имеет стандартную семантику Java, в результате чего независимый экземпляр возвращается прямо из фабричного метода.
Видимость методов @Bean
на языке Java не оказывает непосредственного влияния на результирующее определение бина в контейнере Spring. Вы можете свободно объявлять свои фабричные методы по своему усмотрению в классах, не относящихся к @Configuration
, а также для статических методов в любом месте. Однако обычные методы @Bean
в классах @Configuration
должны быть переопределяемыми, то есть, они не должны быть объявлены как private
или final
.
Методы @Bean
также обнаруживаются для базовых классов данного компонента или конфигурационного класса, а также для методов на Java 8 по умолчанию, объявленных в интерфейсах, реализуемых компонентом или конфигурационным классом. Это позволяет очень гибко подходить к созданию сложных конфигураций, при этом даже множественное наследование возможно осуществить через методы Java 8 по умолчанию, начиная с версии Spring 4.2.
Наконец, один класс может содержать несколько методов @Bean
для одного и того же бина в качестве организации нескольких фабричных методов для использования в зависимости от доступных зависимостей во время выполнения. Это тот же алгоритм, что и при выборе самого "жадного" конструктора или фабричного метода в других сценариях конфигурации: Вариант с наибольшим количеством удовлетворяющих зависимостей выбирается во время построения, аналогично тому, как контейнер выбирает между несколькими @Autowired
конструкторами.
Именование компонентов с автоматическим обнаружением
Если компонент автоматически обнаруживается в процессе сканирования, его имя бина генерируется стратегией BeanNameGenerator
, известной данному сканеру. По умолчанию, любая стереотипная аннотация Spring(@Component
, @Repository
, @Service
и @Controller
), содержащая value
имени, тем самым предоставляет это имя соответствующему определению бина.
Если такая аннотация не содержит value
имени или для любого другого обнаруженного компонента (например, обнаруженного кастомными фильтрами), генератор имен бинов по умолчанию возвращает неполное имя класса без заглавных букв. Например, если были обнаружены следующие классы компонентов, то их имена будут myMovieLister
и movieFinderImpl
:
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Service("myMovieLister")
class SimpleMovieLister {
// ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
Если вы не желаете полагаться на стратегию именования бинов по умолчанию, то можете указать собственную стратегию именования. Во-первых, реализуйте интерфейс BeanNameGenerator
и обязательно включите в него конструктор по умолчанию без аргументов. Затем укажите полное имя класса при конфигурировании сканера, как показано в следующем примере аннотации и определения бина.
BeanNameGenerator
, который по умолчанию использует полное имя класса для генерируемого имени бина. Начиная со Spring Framework 5.2.3, для таких целей можно использовать FullyQualifiedAnnotationBeanNameGenerator
, находящийся в пакете org.springframework.context.annotation
.@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
Как правило, следует указывать имя вместе с аннотацией во всех случаях, в которых другие компоненты могут явно ссылаться на него. С другой стороны, автоматически генерируемые имена подходят для тех случаев, когда контейнер отвечает за связывание.
Предоставление области доступности для автоматически обнаруженных компонентов
Как и в целом в случае с компонентами, управляемыми Spring, стандартной и наиболее распространенной областью доступности для автоматически обнаруженных компонентов является singleton
. Однако иногда может потребоваться иная область доступности, которую можно указать с помощью аннотации @Scope
. Вы можете указать имя области доступности в аннотации, как показано в следующем примере:
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
@Scope("prototype")
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
@Scope
осуществляется только для конкретного класса бина (для аннотированных компонентов) или для фабричного метода (для методов @Bean
). В отличие от определений бинов на XML, здесь нет понятия наследования определений бинов, а иерархии наследования на уровне классов не имеют значения для целей метаданных.Для получения подробной информации о веб-специфических областях доступности, таких как "request" или "session" в контексте Spring, см. раздел "Области доступности Request, Session, Application и WebSocket". Как и в случае с готовыми аннотациями для этих областей доступности, вы также можете составлять свои собственные аннотации, используя мета-аннотации Spring: например, специальную аннотацию, мета-аннотированную @Scope("prototype")
и, возможно, также объявляющую специальный режим с прокси, входящим в область доступности (scoped-proxy mode).
ScopeMetadataResolver
. Обязательно включите конструктор по умолчанию без аргументов. Затем можно указать полностью уточненное имя класса при настройке сканера, как показано в следующем примере аннотации и определения бина:@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
При использовании некоторых не неодиночных областей видимости может потребоваться создание прокси для объектов в области видимости. Для этого для элемента component-scan имеется атрибут scoped-proxy. Три возможных значения: no
, interfaces
и targetClass
. Например, следующая конфигурация приводит к получению стандартных динамических прокси из JDK:
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
// ...
}
@Configuration
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
class AppConfig {
// ...
}
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
Укзание метаданных квалификатора с помощью аннотаций
Примеры в данном разделе демонстрируют использование аннотации @Qualifier
и пользовательских аннотаций квалификаторов для обеспечения тонкого контроля при разрешении компонентов-кандидатов на автоматическое обнаружение и связывание. Поскольку эти примеры были основаны на определениях бинов на XML, метаданные квалификатора были указаны в определениях бинов-кандидатов с помощью qualifier
или дочерних элементов meta
элемента bean
на XML. Если вы полагаетесь на сканирование classpath для автоматического обнаружения компонентов, вы можете предоставить метаданные квалификатора с аннотациями на уровне типов для класса-кандидата. Следующие три примера демонстрируют этот приём:
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Qualifier("Action")
class ActionMovieCatalog : MovieCatalog
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Genre("Action")
class ActionMovieCatalog : MovieCatalog {
// ...
}
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Offline
class CachingMovieCatalog : MovieCatalog {
// ...
}
Генерация индекса компонентов-кандидатов
Хотя сканирование путей класса происходит крайне быстро, можно улучшить производительность запуска больших приложений, создав статический список кандидатов во время компиляции. В этом режиме все модули, которые являются объектами сканирования компонентов, должны задействовать этот механизм.
@ComponentScan
или <context:component-scan/>
должны оставаться неизменными, чтобы запрашивать контекст на сканирование компонентов-кандидатов в определенных пакетах. Если ApplicationContext
обнаруживает такой индекс, он автоматически использует его, а не сканирует classpath.Чтобы сгенерировать индекс, добавьте дополнительную зависимость к каждому модулю, содержащему компоненты, которые являются целями для директив сканирования компонентов. В следующем примере показано, как это сделать с помощью Maven:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.3.24</version>
<optional>true</optional>
</dependency>
</dependencies>
В Gradle 4.5 и более ранних версиях зависимость нужно объявлять в конфигурации compileOnly
, как показано в следующем примере:
dependencies {
compileOnly "org.springframework:spring-context-indexer:5.3.24"
}
В Gradle 4.6 и более поздних версиях зависимость нужно объявлять в конфигурации annotationProcessor
, как показано в следующем примере:
dependencies {
annotationProcessor "org.springframework:spring-context-indexer:5.3.24"
}
Артефакт spring-context-indexer
генерирует файл META-INF/spring.components
, который включается в jar-файл.
spring-context-indexer
должен быть зарегистрирован как обработчик аннотаций, чтобы убедиться, что индекс будет обновляться при обновлении компонентов-кандидатов.META-INF/spring.components
будет найден в пути классов. Если индекс частично доступен для некоторых библиотек (или сценариев использования), но не может быть создан для всего приложения, можно вернуться к обычному типу организации пути классов (как если бы индекс вообще отсутствовал), установив spring.index.ignore
в true
, либо как системное свойство JVM, либо через механизм SpringProperties
.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ