hubbabubba
hubbabubba

Reputation: 997

How does Java Spring @Autowired work with interface inheriting from several interfaces?

I have a Java Spring Framework project. After a bit of googling I found a way to include custom JPA methods into a JpaRepository. The injection of my repository into my service class using @Autowired works, but I can't understand how Spring handles the injection in this case. Could someone explain how Spring does the injection of CalendarEventRepository into CalendarEventService when the method implementations are in separate classes. It finds the JpaRepository implementation somewhere and my own custom implementation class with my custom method. Howcome their methods are accessible through the same reference variable calendarEventRepository? Bonus question: how does Spring find and instantiate the implementation for JpaRepository?

public interface CalendarEventRepository extends JpaRepository<CalendarEvent, Long>, CalendarEventRepositoryCustom { }

public interface CalendarEventRepositoryCustom {
public List<CalendarEvent> findCalendarEventsBySearchCriteria(CalendarEventSearchCriteria searchCriteria);
}

public class CalendarEventRepositoryImpl implements
CalendarEventRepositoryCustom {
public List<CalendarEvent> findCalendarEventsBySearchCriteria(CalendarEventSearchCriteria searchCriteria) {
     }
}

public class CalendarEventService {
@Autowired
CalendarEventRepository calendarEventRepository;
...
calendarEventRepository.delete(calendarEvent);
...
return  calendarEventRepository.findCalendarEventsBySearchCriteria(searchCriteria);
...
}

Thanks in advance!

Upvotes: 0

Views: 877

Answers (2)

PresentProgrammer
PresentProgrammer

Reputation: 703

When you are using Spring JPA repository interface (extend JpaRepository class), the important thing is that the implementation of the interface is generated at runtime. Method names are used by Spring to determine what the method should (since you have written the name findCalendarEventsBySearchCriteria correctly, it means that you already know that). In your particular case, CalendarEventRepository extends CalendarEventRepositoryCustom and therefore has a method findCalendarEventsBySearchCriteria(...), and also extends JpaRepository<CalendarEvent, Long>, which means that it should be treated as JPA repository, and the corresponding implementation should be generated.

To enable the generation of the repository implementation, you need to either include <jpa:repositories base-package="..." /> to your XML configuration file, or @Configuration @EnableJpaRepositories(basePackage = "...") When you have these, that's all the information Spring needs to generate (instantiate) repository and add it to application contexts, and the inject it into other beans. In your case, @Autowired CalendarEventRepository calendarEventRepository; specifies where it should be injected. I guess it more answers bonus question than the main one, but seems better to start with it.

I haven't yet touched CalendarEventRepositoryImpl. You should use such class if you want to drop the mentioned generation of repository implementation for particular methods. Spring looks for a class which name equals to repository interface's name + "Impl". If such class exists, Spring merges its methods with generated ones. So, see for yourself whether auto-generated findCalendarEventsBySearchCriteria method fits your needs or you want to implement it yourself. If the generated one fits, you should consider removing CalendarEventRepositoryImpl at all.

Upvotes: 2

Juned Jabbar Shaikh
Juned Jabbar Shaikh

Reputation: 36

  1. Could someone explain how Spring does the injection of CalendarEventRepository into CalendarEventService when the method implementations are in separate classes.

Answer: First, and most important - all Spring beans are managed - they "live" inside a container, called "application context".

Regardless of which type of configuration you are usin (Java or xml based) you enable "Component Scanning" this helps Spring determine which resource to inject.

How spring determines which bean to inject:

  • Matches the names.
  • Matches the type.

You even use Qualifiers to narrow down the search for spring.

  1. It finds the JpaRepository implementation somewhere and my own custom implementation class with my custom method. Howcome their methods are accessible through the same reference variable calendarEventRepository?

This is more of a java core question of inheritance. Since JpaRepository, CalendarEventRepositoryCustom and CalendarEventRepository are the base classes (implementations) of your CalendarEventRepositoryImpl so any method/field that is public or protected is available to CalendarEventRepositoryImpl class.

Here you are using "Program though interface" your reference variable here is calendarEventRepository which is an interface (parent) and that is why you are able to access the fields/methods.

  1. Bonus question: how does Spring find and instantiate the implementation for JpaRepository?

In spring configuration (java based) you tell spring to search for JPARepositories as below:

@EnableJpaRepositories(
        basePackages =  {
    "com.package"}
, entityManagerFactoryRef = "EntityManagerFactory", transactionManagerRef = "jpaTransactionManager"
    )

This is how spring gets to know which beans to create.

I recommend reading out Spring in Action (2nd to 4th Edition) by Craig Walls.

You can as well go through the https://spring.io/docs

Annotations (Autowired, Inject, your custom) works because of AOP. Read a bit about AOP and you will know how that works.

Upvotes: 1

Related Questions