Reputation: 997
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
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
Reputation: 36
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:
You even use Qualifiers to narrow down the search for spring.
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.
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