2015-01-30 2 views
4

У меня есть один базовый интерфейс и две реализацийSpring autowire несколько Реализации услуг

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"); 
    } 
} 

В моем основном методе попытаться вызвать эту реализацию две служб следующим образом:

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(); 
    } 
} 

Это даст ошибку компиляции , так как birdService не может найти метод fly(). Тогда я подумал, может быть причина я autowire AnimalService вместо BirdServiceImpl, поэтому я изменить свой autowire код из этого:

@Autowired 
    @Qualifier("birdService") 
    private AnimalService birdService; 

изменение:

@Autowired 
    private BirdServiceImpl birdService; 

Но это даст мне ошибку времени выполнения, который «не может найти bean BirdServiceImpl». У меня есть много документов, некоторые говорят, что используйте @Resource. Но это не работает для меня. Некоторые говорят, что регистр в контексте Spring Context, в то время как вся моя регистрация бобов выполняется аннотацией. Я не хочу касаться контекста Весны.

Теперь Мое решение добавить новый интерфейс

public interface BirdService extends AnimalService 
{ 
    public void fly(); 
} 

И пусть мой BirdServiceImpl реализовать этот интерфейс

public class BirdServiceImpl extends AnimalServiceImpl extends BirdService 
    { 
     public void fly() 
     { 
      System.out.println("i'm flying"); 
     } 
    } 

И моя главная изменить класс к этому:

public class test 
{ 
    @Autowired 
    private AnimalService animalService; 
    @Autowired 
    private BirdService birdService; 

    public static void main(String[] args) 
    { 
     animalService.eat(); 
     birdService.eat(); 
     birdService.fly(); 
    } 
} 

Сейчас нормально . Но для меня это не идеально. Если я использую простой java, я могу просто написать один интерфейс и несколько реализаций. В основном методе я могу выбрать, какую реализацию использовать. Почему весной мне нужно создать новый интерфейс для каждой новой реализации, чтобы запустить мою программу.

Я хочу знать, есть ли лучший подход для моего сценария?

+2

Ваш код, как есть, не будет работать с простой java. 'AnimalService' не имеет метода' fly' и независимо от того, что вы используете Spring или plain java (heck spring is java), он не найдет метод. Инъекция «BirdServiceImpl» завершится неудачно, потому что в зависимости от вашей конфигурации прокси-сервер будет создан для применения АОП. По умолчанию используются интерфейсы, поскольку вы реализуете интерфейс, поэтому ваш bean-компонент будет «AnimalService», но не одной из реализаций, который будет динамическим прокси-сервером, реализующим все интерфейсы. Который, imho, i, как и должно быть, как вы должны программировать на интерфейсы. –

+0

Вы правы, если я использую простой java, все равно не могу вызвать fly(), если я не инициализирую bean-компонент таким образом: BirdServiceImpl birdService = new BirdServiceImpl(); – zzyclark

ответ

2

В своем вопросе вы фактически обнажая два вопроса:

1.Вопрос о наследовании

Эта проблема не зависит от Spring Framework, но объясняется вашим неправильным представлением о наследовании. Если вы заявляете свое обслуживание как AnimalService, вы, очевидно, можете использовать его только как AnimalService, вне зависимости от его реальной реализации. Если вы хотите использовать конкретные методы реализации, вам нужно бросить свой объект.

2. «автоматического связывания класса» вопрос

Это должно нормально работать весной, так что если ваш код не работает, зависит от конфигурации контекста. Возможно, вы также используете AOP или транзакции в своем приложении, Если это так, включен автопрокси-генератор. Это может привести к вашей проблеме.

Посмотрите на этот вопрос: Spring Autowiring class vs. interface?. И заметьте, что:

При использовании autoproxies, вам нужно запрограммировать на интерфейс, а не реализация

3. Только примечание

Как вы можете использовать () в конце имени интерфейса/класса Java?

+0

извините за скобу, неправильно напечатано – zzyclark

+0

Да, я также использую аннотацию транзакции для каждого моего сервиса, я думаю, мне нужно проверить мой AOP. Я обновляю свой код – zzyclark

+0

@zzyclark, в этом случае вы можете использовать 'Autowiring' только на интерфейсах. – davioooh

1

Как я уже прочитал в вашем вопросе, проблема была устранена путем создания Interface для унаследованного класса BirdService. Вы только жалуетесь, потому что вам нужно создать новый интерфейс ...

Когда я читаю ваш вопрос, возникает вопрос: какой АОП вы используете? Возможно, вам нужно добавить CGLIB в свой путь к классам (или Maven POM или Gradle).

Чтение некоторых из Spring AOP documentation, я нашел это:

Если класс целевого объекта, который должен быть проксированным (далее просто называют в качестве целевого класса) Безразлично» t реализовать любые интерфейсы , тогда будет создан прокси-сервер на основе CGLIB. Это самый простой сценарий , поскольку прокси-серверы JDK основаны на интерфейсах, а интерфейсы означают, что проксирование JDK даже невозможно.

Смежные вопросы