Tenho um componente que desejo excluir de um @ComponentScan
em particular @Configuration
:
@Component("foo") class Foo {
...
}
Caso contrário, parece colidir com alguma outra classe em meu projeto. Não entendo totalmente a colisão, mas se eu comentar a @Component
anotação, as coisas funcionam como eu quero. Mas outros projetos que dependem desta biblioteca esperam que esta classe seja gerenciada pelo Spring, então eu quero pular apenas no meu projeto.
Tentei usar @ComponentScan.Filter
:
@Configuration
@EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}
mas não parece funcionar. Se eu tentar usar FilterType.ASSIGNABLE_TYPE
, recebo um erro estranho sobre não ser capaz de carregar alguma classe aparentemente aleatória:
Causado por: java.io.FileNotFoundException: recurso de caminho de classe [junit / framework / TestCase.class] não pode ser aberto porque não existe
Eu também tentei usar type=FilterType.CUSTOM
o seguinte:
class ExcludeFooFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
return metadataReader.getClass() == Foo.class;
}
}
@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}
Mas isso não parece excluir o componente da varredura como eu desejo.
Como faço para excluí-lo?
fonte
Usar tipos explícitos em filtros de verificação é feio para mim. Acredito que uma abordagem mais elegante é criar a própria anotação do marcador:
@Retention(RetentionPolicy.RUNTIME) public @interface IgnoreDuringScan { }
Marque o componente que deve ser excluído com ele:
@Component("foo") @IgnoreDuringScan class Foo { ... }
E exclua esta anotação de sua verificação de componente:
@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class)) public class MySpringConfiguration {}
fonte
@Component
, mas não acho que seja isso que a pergunta está perguntandoOutra abordagem é usar novas anotações condicionais. Desde o Spring 4 simples, você pode usar a anotação @Conditional:
@Component("foo") @Conditional(FooCondition.class) class Foo { ... }
e definir a lógica condicional para registrar o componente Foo:
public class FooCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // return [your conditional logic] } }
A lógica condicional pode ser baseada no contexto, porque você tem acesso ao bean factory. Por exemplo, quando o componente "Bar" não está registrado como bean:
return !context.getBeanFactory().containsBean(Bar.class.getSimpleName());
Com o Spring Boot (deve ser usado para CADA novo projeto Spring), você pode usar estas anotações condicionais:
@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnExpression
@ConditionalOnJava
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnNotWebApplication
@ConditionalOnProperty
@ConditionalOnResource
@ConditionalOnWebApplication
Você pode evitar a criação de classes de Condição dessa maneira. Consulte a documentação do Spring Boot para obter mais detalhes.
fonte
Caso você precise definir dois ou mais critérios excludeFilters , você deve usar a matriz.
Por exemplo, nesta seção de código, desejo excluir todas as classes do pacote org.xxx.yyy e outra classe específica, MyClassToExclude
@ComponentScan( excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.xxx.yyy.*"), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyClassToExclude.class) })
fonte
Eu tive um problema ao usar @Configuration , @EnableAutoConfiguration e @ComponentScan ao tentar excluir classes de configuração específicas, o que não funcionou!
Eventualmente resolvi o problema usando @SpringBootApplication , que, de acordo com a documentação do Spring, tem a mesma funcionalidade dos três acima em uma anotação.
Outra dica é tentar primeiro sem refinar sua verificação de pacote (sem o filtro basePackages).
@SpringBootApplication(exclude= {Foo.class}) public class MySpringConfiguration {}
fonte
No caso de excluir o componente de teste ou configuração de teste, Spring Boot 1.4 introduziu novas anotações de teste
@TestComponent
e@TestConfiguration
.fonte
Eu precisava excluir um @Aspect @Component de auditoria do contexto do aplicativo, mas apenas para algumas classes de teste. Acabei usando @Profile ("audit") na classe de aspecto; incluindo o perfil para operações normais, mas excluindo-o (não o coloque em @ActiveProfiles) nas classes de teste específicas.
fonte