I have one base interface and two implementations
public interface AnimalService
{
public void eat();
}
@Service("animalService")
@Transactional
public class AnimalServiceImpl implements AnimalService
{
@Override
public void eat()
{
System.out.println("i'm eating");
}
}
@Service("birdService")
@Transactional
public class BirdServiceImpl extends AnimalServiceImpl
{
public void fly()
{
System.out.println("i'm flying");
}
}
In my main method try to call this two service implementation in this way:
public class test
{
@Autowired
private AnimalService animalService;
@Autowired
@Qualifier("birdService")
private AnimalService birdService;
public static void main(String[] args)
{
animalService.eat();
birdService.eat();
birdService.fly();
}
}
This will give compilation error, since birdService can't find method fly(). Then I thought maybe the reason is i autowire AnimalService instead of BirdServiceImpl, So i change my autowire code from this:
@Autowired
@Qualifier("birdService")
private AnimalService birdService;
change to :
@Autowired
private BirdServiceImpl birdService;
But this will give me a runtime error, which is "can't find bean BirdServiceImpl". I have google a lot of document, some say use @Resource. But this doesn't work for me. Some say register the bean in Spring Context, while all my bean registration is done by annotation. I don't want to touch Spring Context.
Now My solution is to add a new interface
public interface BirdService extends AnimalService
{
public void fly();
}
And let my BirdServiceImpl to implement this interface
public class BirdServiceImpl extends AnimalServiceImpl extends BirdService
{
public void fly()
{
System.out.println("i'm flying");
}
}
And my main class change to this:
public class test
{
@Autowired
private AnimalService animalService;
@Autowired
private BirdService birdService;
public static void main(String[] args)
{
animalService.eat();
birdService.eat();
birdService.fly();
}
}
Now is ok . But for me, this is not perfect. If I use plain java, i can just write single interface and multiple implementation. In the main method I can choose which implementation to use. Why in spring, i have to build a new interface for each new implementation in order to let my program run.
I want to know is there any better approach for my scenario?
In your question you are actually exposing two issues:
1. Inheritance issue
This problem doesn't depends on Spring Framework, but is due by your misconception about inheritance.
If you declare your service as AnimalService
, you obviously can use it only as an AnimalService
, regardless its real implementation.
If you want to use concrete implementations methods, you need to cast your object.
2. 'Autowiring a class' issue
This should normally work in Spring, so if your code doesn't work depends on your context configuration. Maybe you are also using AOP or transactions in your app, If so, an autoproxy generator is enabled. This could cause your problem.
Take a look at this question: Spring Autowiring class vs. interface?. And note that:
When using autoproxies, you need to program to the interface, not the implementation
3. Just a note
How can you use ()
at the end of a Java interface/class name?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With