#java #spring #spring-boot
#java #spring #spring-загрузка
Вопрос:
У меня есть куча модулей (скажем, 3). Два модуля основаны на Spring boot, а другой — на Spring. Скажем, модуль 1 — Модуль SpringBoot 2 — Модуль Spring Boot 3 — Общий модуль, основанный только на Spring
Определен модуль 3 @Файл конфигурации, который должен выбираться только модулем 2, а не 1.
Я перепробовал кучу вещей, чтобы исключить файл конфигурации. Например:-
@SpringBootApplication
@ComponentScan(basePackages = {"com.adobe"}
, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {WorkerConfig.class, WorkerExecutors.class, Worker.class})})
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Но все же класс @Configiration не исключается, и Spring пытается загрузить его в контексте приложения, чего я не хочу. Мой класс конфигурации
@Configuration
public class WorkerConfig {
@Bean
public WorkerExecutors workerExec() {
WorkerExecutors executors = new WorkerExecutors();
return executors;
}
}
Также я читаю в аннотации @ComponentScan, что
* <p>Note that the {@code <context:component-scan>} element has an
* {@code annotation-config} attribute; however, this annotation does not. This is because
* in almost all cases when using {@code @ComponentScan}, default annotation config
* processing (e.g. processing {@code @Autowired} and friends) is assumed. Furthermore,
* when using {@link AnnotationConfigApplicationContext}, annotation config processors are
* always registered, meaning that any attempt to disable them at the
* {@code @ComponentScan} level would be ignored.
Похоже, исключение при проверке компонентов не сработает. Помимо описанного выше, я также пытался исключить использование
@SpringBootApplication(exclude= {WorkerExecutors.class, Worker.class,WorkerConfig.class})
public class Application {
Но spring boot выдает
java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes:
- com.adobe.repository.worker.lib.config.WorkerConfig
- com.adobe.acp.repository.worker.lib.core.WorkerExecutors
- com.adobe.acp.repository.worker.lib.core.Worker
Любая идея, как я могу отключить компонентное сканирование модуля загрузки, отличного от spring, в модуле загрузки spring, кроме установки в другой пакет. Я не хочу помещать в другой пакет.
Любая помощь приветствуется!!
Комментарии:
1. Несколько хакерским способом сделать это было бы снабдить
Worker
конфигурации@ConditionalOnProperty
аннотацией, а затем установить свойство только для модуля 2.2. Да, это работает.. Я использовал conditional, а не condition by property, поскольку это приводит к зависимости spring boot, которой я хотел избежать .. но вы говорите, что это халтурно?
3. Это своего рода хакерство, потому что, как упоминалось в некоторых других комментариях, в идеале вы бы разделили свои модули так, чтобы только код, который должен находиться в classpath, фактически находился в classpath (т. Е. модуль 1 даже не должен иметь доступа к нежелательным конфигурационным классам модуля 3). Используя «поэтапное» сканирование компонентов, подобное этому, вы можете столкнуться с ошибками / проблемами в будущем, когда что-то от Worker действительно должно присутствовать в модуле 1, в конце концов, и это заставит вас переработать этот подход. Но если у вас это работает и вы можете справиться с этими проблемами, это тоже правильный путь.
4. Соглашайтесь с этим. Но на данный момент это одноразовые классы, поэтому нет особого смысла перемещать их из classpath. Но да, когда подобные вещи увеличиваются, определенно, код может давать ошибки и его трудно поддерживать.
Ответ №1:
Вы можете попробовать это, у меня это работает:
@SpringBootApplication
@ComponentScan(excludeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE, classes = {WorkerConfig.class, WorkerExecutors.class, Worker.class})})
Комментарии:
1. На самом деле этого не будет.
2. Я обнаружил, что это сработало, только если я указал
basePackages
свойство в@ComponentScan
аннотации.
Ответ №2:
Пакеты автоматической настройки находятся в org.springframework.boot.autoconfigure. Вот причина, по которой вы не можете сделать:
@SpringBootApplication(exclude= {WorkerExecutors.class, Worker.class,WorkerConfig.class})
Spring делает то, что вы говорите делать. Вы вызываете:
@ComponentScan(basePackages = {"com.adobe"}
, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {WorkerConfig.class, WorkerExecutors.class, Worker.class})})
Поэтому Spring не будет загружать ни один из этих рабочих классов. Вот почему Spring не «выполняет» ваши классы, помеченные @Configuration.
Тем не менее, то, что вы пытаетесь сделать, для меня не имеет смысла. Похоже, у вас есть «модули» (классы Java), но все они являются частью одного и того же контекста spring. Если у вас есть единственный контекст Spring, то вы можете указать Spring загружать некоторые классы @Configuration, а не некоторые другие. Затем из ваших «модулей» вы можете вводить все, что вам нужно. Модуль 1 будет вводить компоненты из модуля 3, а модуль 2 — нет. Вот так просто.
Если по какой-то причине вам действительно нужно запретить модулю 2 доступ к компонентам из модуля 3, но при этом сохранить модуль 3 видимым из модуля 1, то я бы разделил модуль 1 и модуль 2 в двух разных приложениях Spring Boot, а модуль 3 стал общим кодом. Но этот подход может нарушить вашу текущую архитектуру.
ОБНОВЛЕНИЕ От 29 марта 2019 г.
Попробуйте это:
@SpringBootApplication
@ComponentScan(basePackages = { "com.myapp" }, excludeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = { MyClass2.class }) })
У меня это сработало. У меня есть MyClass и MyClass2, и MyClass загружен, а MyClass2 — нет. Я попробовал это с Spring Boot 1.5.9.RELEASE и Spring Bom для всех зависимостей.
Комментарии:
1. Spring загружает рабочие классы, вот в чем проблема. Я хочу, чтобы он не загружал их, но текущий код не работает. Кроме того, думаю, я не был подробен в своем вопросе. Модуль 1 и модуль 2 являются отдельными приложениями Spring boot, а модуль 3 представляет собой общий код. Здесь находятся мои рабочие классы (включая config). Они хотят загружаться модулем 2 и другими модулями, но не модулем 1, но некоторые другие классы конфигурации, присутствующие в модуле 3, требуются модулю 1. Конечно, я также могу разделить модуль 3 на модуль 4, где модуль 1 никогда не сканирует 4, но я смотрю, как это сделать в текущей структуре кода, о которой я упоминаю
2. Что ж, если модуль 3 содержит код, который необходим в модуле 2, но не в модуле 1, то модуль 3 действительно является обычным кодом. Я знаю, что вы это знаете, просто указывая на проблему. Теперь, по моему опыту, использование @Configuration в обычном коде не так уж хорошо, потому что оно будет сканироваться всеми подпроектами (или модулями, или как вы хотите это назвать). Что мне очень помогло, так это поместить код в общее место, но не аннотации Spring, а просто код. Допустим, у вас есть модуль 3 с кучей кода Java, но без аннотаций Spring. Продолжайте читать следующий комментарий ->
3. Затем, если модулю 2 требуется код из модуля 3, то вам нужно создать класс конфигурации в модуле 2, который создает все @Beans, используя типы / код из модуля 3. Имеет смысл? Это правильный путь.
4. Звучит справедливо. Но единственное, что модуль 3 будет вызываться не только модулем 2, но и другими модулями (4,5), так что on..so в конечном итоге мы будем дублировать код во всех модулях.. это то, чего я хочу избежать..
5. Ну, на самом деле это не дублирующий код. Краткий пример: Раньше я работал в проекте, в котором было около 10 приложений springboot. Все они были настроены на использование компонента фильтра ключей API. Итак, логика фильтрации ключей API была помещена в класс, называемый APIKeyFilter, внутри общего модуля Java. Затем каждое приложение Spring Boot создало бы компонент, подобный этому: @Bean public APIKeyFilter apikeyfilter(){}