0
votes

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.

2

2 Answers

1
votes

@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"/>
1
votes

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