英文:
Spring exclude filter
问题
在 application-context.xml 中:
<context:component-scan base-package="com.myApp">
<context:exclude-filter type="assignable" expression="com.myApp.MyService"/>
</context:component-scan>
<bean id="myService" class="com.myApp.ExtendedService" />
在 Main.java 中:
@SpringBootApplication
@ImportResource(locations = {"classpath:application-context.xml"})
public class Main{
//...
}
在 ExtendedService 中:
@Service
public class ExtendedService extends MyService{
//...
}
但是当我启动时,出现了 "Invalid Bean definition because myService is bound" 错误。如何排除原始的 MyService?
异常信息:
> Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: 在 URL [file:svc.xml] 中定义的名为 'myService' 的无效 bean 定义:无法为 bean 'myService' 注册 bean 定义 [通用 bean:类 [com.myApp.ExtendedService];作用域=;抽象=false;lazyInit=false;autowireMode=1;dependencyCheck=0;autowireCandidate=true;primary=false;factoryBeanName=null;factoryMethodName=null;initMethodName=null;destroyMethodName=null;在 URL [file:svc.xml] 中定义]:已经存在 [通用 bean:类 [com.myApp.MyService];作用域=singleton;抽象=false;lazyInit=false;autowireMode=0;dependencyCheck=0;autowireCandidate=true;primary=false;factoryBeanName=null;factoryMethodName=null;initMethodName=null;destroyMethodName=null;在 URL [jar:file:/.m2/repository/com/myApp/myLib-1.0.0.jar!/com/myApp/MyService.class] 中定义]。
英文:
Inside application-context.xml:
<context:component-scan base-package="com.myApp">
<context:exclude-filter type="assignable" expression="com.myApp.MyService"/>
</context:component-scan>
<bean id="myService" class="com.myApp.ExtendedService" />
Inside Main.java:
@SpringBootApplication
@ImportResource(locations = {"classpath:application-context.xml"})
public class Main{
//...
}
Inside ExtendedService:
@Service
public class ExtendedService extends MyService{
//...
}
But when I start, I get Invalid Bean definition because myService is bound error. How to exclude the original MyService?
Exception:
> Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'myService' defined in URL [file:svc.xml]: Cannot register bean definition [Generic bean: class [com.myApp.ExtendedService]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [file:svc.xml]] for bean 'myService': There is already [Generic bean: class [com.myApp.MyService]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/.m2/repository/com/myApp/myLib-1.0.0.jar!/com/myApp/MyService.class]] bound.
答案1
得分: 1
@SpringBootApplication 正在对同一(以及子)包进行包扫描。这相当于 @Configuration @EnableAutoConfiguration @ComponentScan。如果您不想要包扫描,可以用另外两个来替代。
@Configuration
@EnableAutoConfiguration
@ImportResource(locations = {"classpath:application-context.xml"})
public class Main{
//...
}
EDIT:您可以在 ExtendedService 上使用 @Primary,上下文将使用这个而不是 MyService,这样您就不需要在扫描中排除它。这只在 MyService 不是主要时才有效。
@Primary
@Service
public class ExtendedService extends MyService{
//...
}
EDIT2:由于这两个服务都可分配给 MyService,所以您不能使用 assignable 来排除,可以使用正则表达式。
<context:exclude-filter type="regex" expression="com.myApp.MyService"/>
英文:
@SpringBootApplication is doing an package scan on the same (and sub) packages. This is the equivqlent of @Configuration @EnableAutoConfiguration @ComponentScan. You can replace by the 2 others if you don't want a package scan.
@Configuration
@EnableAutoConfiguration
@ImportResource(locations = {"classpath:application-context.xml"})
public class Main{
//...
}
EDIT: you can use @Primary on ExtendedService, the context will use this one instead of MyService, then you don't need to exclude in the scan. This is working only if MyService is not primary.
@Primary
@Service
public class ExtendedService extends MyService{
//...
}
EDIT2: you can't exlude with assignable as both services are assignable to MyService use regex.
<context:exclude-filter type="regex" expression="com.myApp.MyService"/>
答案2
得分: 1
你不必真的使用XML配置,尽管它们仍然受支持,但看起来确实过时了。
基本上有两条不同的路径可以选择:
解决方案1
使用@Conditional
,仅在满足某些条件(通过属性、类路径中存在的类,甚至是自定义逻辑表示)时加载ExtendedService
的bean。
@Service
@ConditionalOnProperty(name = "feature.x.enabled", havingValue = "true")
public class ExtendedService extends MyService {
}
这将导致只有在提供了以下属性的情况下才会加载该bean(可以在application.properties
/ yaml
或者任何Spring Boot识别的方式中设置):
feature.x.enabled=true
到目前为止,这是我可以推荐的最清晰的解决方案。
解决方案2
另一种解决方案是基于自定义组件扫描路径的能力。默认情况下,扫描的是与主类(用@SpringBootApplication
注解的类)相同的包,以及其在任何层级上的所有子包。
因此,如果你想要将这个类从组件扫描过程中排除掉,可以这样做:
@SpringBootApplication
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = ExtendedService.class))
public class Main {
public static void main(...) {...}
}
请注意,有许多类型的过滤器,你可能希望阅读这篇教程以获取更多信息。
英文:
You don't really have to work with XML configurations, they're still supported but look really outdated.
Basically there are two different paths you can take:
Solution 1
Use @Conditional
to load the bean of ExtendedService
only when some condition (expressed via property, presence of class in a classpath, or even custom logic) is met
@Service
@ConditionalOnProperty(name = "feature.x.enabled", havingValue = "true")
public class ExtendedService extends MyService {
}
This will lead to the situation that the bean will be loaded only if the property is supplied as follows (in application.properties / yaml or in any other way that spring boot recognizes):
feature.x.enabled=true
By far this is the cleanest solution I can recommend
Solution 2
Another solution is based on the ability to customize paths that are subject to component scanning. By default is the same package where the main class (the one annotated with @SpringBootApplication
resides) and all its subpackages at any level.
So if you want to exclude this class from component scanning process you can do the following:
@SpringBootApplication
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = ExtendedService .class))
public class Main {
public static void main(...) {...}
}
Note, there are many types of filters you might want to read this tutorial for more information
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论