Spring排除过滤器

huangapple go评论81阅读模式
英文:

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:

&lt;context:component-scan base-package=&quot;com.myApp&quot;&gt;
        &lt;context:exclude-filter type=&quot;assignable&quot; expression=&quot;com.myApp.MyService&quot;/&gt;
&lt;/context:component-scan&gt;

&lt;bean id=&quot;myService&quot; class=&quot;com.myApp.ExtendedService&quot; /&gt;

Inside Main.java:

@SpringBootApplication
@ImportResource(locations = {&quot;classpath:application-context.xml&quot;})
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 = {&quot;classpath:application-context.xml&quot;})
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.

&lt;context:exclude-filter type=&quot;regex&quot; expression=&quot;com.myApp.MyService&quot;/&gt;

答案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 = &quot;feature.x.enabled&quot;, havingValue = &quot;true&quot;)
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

huangapple
  • 本文由 发表于 2020年9月2日 12:44:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63698836.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定