How to specify which subclass Spring should use

12,974

Solution 1

Spring eagerly instantiates singleton beans as stated in the documentation:

By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.

which might explain why both @Components are created.

To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.

Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:

public interface MyService {
    public String foobar(int baz);
}

public static class CommonBehavior {
    // whatever is used by Superclass and Subclass
}

@Component @Lazy
public class FormerSuperClass implements MyService {
   private final CommonBehavior ...;
   ...
}

@Component @Lazy
public class FormerSubClass implements MyService {
   private final CommonBehavior ...;
   ...
}

Good luck!

Solution 2

You can use @Qualifier("some name") annotation. There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/

Solution 3

There are 2 methods: Use @Qualifier("SubclassName") Or Mark your subclass as @Component and declare the subclass when @Autowired

In your case:

  1. Use @Qualifier("SubclassName")

    @Component
    public class Superclass {
        // stuff
    }
    
    @component
    public class Subclass extends Superclass {
        // overridden stuff
    }
    
    public class AService {
    
        @Autowired
        @Qualifier("Subclass")
        private Superclass superclass;
    
        // service stuff
    }
    

2.Mark your subclass as @Component and declare the subclass when @Autowired

    public class Superclass {
        // stuff
    }

    @component
    public class Subclass extends Superclass {
        // overridden stuff
    }

    public class AService {

        @Autowired
        private Subclass subclass;

        // service stuff
    }
Share:
12,974
Kovalsky
Author by

Kovalsky

Updated on June 04, 2022

Comments

  • Kovalsky
    Kovalsky about 2 years

    In my spring-based project I have a core module ('core') with a class

    @Component
    public class Superclass {
        // stuff
    }
    

    instances of which are injected by type throughout the code like this:

    public class AService {
    
        @Autowired
        private Superclass superclass;
    
        // service stuff
    }
    

    I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:

    @component
    public class Subclass extends Superclass {
        // overridden stuff
    }
    

    The other module ('module2') uses Superclass as is.

    Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:

    @Configuration
    public class Module2Configuration {
    
        @Bean
        public Superclass superclass(){
            return new Subclass();
        }
    }
    

    When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?

  • Kovalsky
    Kovalsky about 11 years
    thanks, I thought of that, but the 'core' module doesn't know anything about 'module1's Subclass, and I want to use it everywhere 'core's code expects Superclass. I can't figure, how should I qualify AService's field so it would know more than without a qualifier. Or should I somehow qualify Subclass? Or both? Could you elaborate on that?
  • Jens Birger Hahn
    Jens Birger Hahn about 11 years
    hey, I'm not sure if I got your application structure and intentions right, so please be forgiving :-). Do both implementations have to be active in the same application/application context? Maybe you can remove the @Component annotation because using @Bean you are creating a new instance anyway? My usual strategy is to create a separate interface (from SuperClass), put it into 'core' and create the required implementations separately (maybe in module1 and module2). I hope I'm coming closer to your needs...
  • Kovalsky
    Kovalsky about 11 years
    I think I will stick with the separate interface in the core and implementation in the modules as you suggested. But the original idea was that the 'core' module would be a full-blown app with its own spring configuration, not knowing about other modules, and 'module1' would extend one of the core's beans (Superclass) changing its behavior slightly (in Subclass) and then tell spring to use that instead creating a slightly different version of the app. I believe I failed to make it clear from the question. My bad.
  • Jens Birger Hahn
    Jens Birger Hahn about 11 years
    I'd like to give you more hints but it's hard to tell without more context if other options would be more suitable. If you can invest another hour have a look at the Spring documentation. It has lots of little examples.