Reputation: 2063
I am trying to implement Constructor based Dependency Injection with Spring. From Spring 4.3 annotations are not required for constructor injection, so my class looks like this:
@RestController
public class CardController {
private IDeckManager _deckManager;
public CardController(IDeckManager deckManager){
_deckManager = deckManager;
}
@RequestMapping("/preparedeck")
public void PrepareDeck(){
_deckManager.InitializeDeck();
_deckManager.ShuffleDeck();
}
}
where IDeckManager is:
public interface IDeckManager {
void InitializeDeck();
void ShuffleDeck();
}
and the actual implementation of IDeckManager is:
public class DeckManager implements IDeckManager {
public Stack<Card> deck;
public DeckManager() {
deck = new Stack<Card>();
}
@Override
public void InitializeDeck() {
for (int i = 0; i < ICard.Suit.length; i++) {
for (int j = 0; i < ICard.Values.length; i++) {
deck.add(new Card(ICard.Suit[i], ICard.Values[j]));
}
}
}
@Override
public void ShuffleDeck() {
Collections.shuffle(deck);
}
}
Unfortunately at runtime it says that: Parameter 0 of constructor in CardController required a bean of type IDeckManager that could not be found.
What am I missing to make the DI work properly?
Upvotes: 2
Views: 3090
Reputation: 42501
As our colleagues already have stated, the DeckManager
class has to be managed by Spring and putting a @Component
or @Service
annotation will resolve the issue.
However I would like to clarify one additional thing here that might save you from a possible bug.
Spring beans by default are singletons, so there will be a single instance of DeckManager
injected by spring to controller. I assume it should manage deck of cards.
So when you'll call /prepareDeck
it will indeed create a deck and will fill it with the cards, so far so good. However, what if you (or someone else) will call this HTTP method once again?
The answer is that it will create an another series of cards and will put it to the stack. Essentially it will add another N cards per each invocation which is probably not what you want.
Another use-case: What if two (or more) requests to "initialize deck" will be called simultaneously? The internal stack will contain a strange mix of cards... Again, probably not your goal.
Its possible to create an "init" method for deck manager and annotate it with @PostConstruct
annotation. In this method you can create a deck and you won't need the HTTP method. Spring will call this method exactly once during the initialization.
Upvotes: 1
Reputation: 821
DeckManager
should be a component of Spring - @Component
, @Service
, etc. Or just @Bean
.
And, please, Java and Spring have own naming convention ... names InintializeDeck
and ShuffleDeck
are not correct for method names! Use initializeDeck
and shuffleDeck
.
Upvotes: 1
Reputation: 58792
Spring need to identify DeckManager
as Spring managed bean, if you use component scan add @Service
or @Component
annotation on implementation
@Service
public class DeckManager implements IDeckManager {
Or add it in Configuration class as a Bean
@Bean
IDeckManager deckManager() {
return new DeckManager();
}
Upvotes: 2