Generic dependency injection
Spring 4.0 has a number of new features, one of the most important being dependency injection support for generics beans. Generic dependency injection allows us to use Spring for dependency injection while taking advantage of generics to simplify code and increase its reusability without adding more code. Spring defaults to dependency injection by field class, and a new feature in Spring4 is that generic concrete types are also used as a classification method for classes (Qualifier).
background
Suppose there are two entity classes Student and Teacher
@Data
public class Student implements IEntity{
private long id;
}
@Data
public class Teacher implements IEntity{
private long id;
}
Copy the code
Entity storage, is through warehousing operation, generally all physical warehousing methods are consistent, only the specific entity type is not the same, the definition of warehousing interface
public interface IRepository<TEntity extends IEntity>{ void add(TEntity entity); List<TEntity> findAll(); . }Copy the code
Defines the base class for the repository implementation, in this case, using List storage
public abstract class BaseRepository <TEntity extends IEntity> implements IRepository<TEntity>{
List<TEntity> datasource = new ArrayList<>();
@Override
public void add(TEntity entity){
this.datasource.add(entity);
}
@Override
public List<TEntity> findAll(){
return datasource;
}
}
Copy the code
Generic dependency injection beans
BaseRepository is an abstract class that is not suitable for injection into Spring. Define a bean that can be injected
@Repository()
@Scope("prototype")
public class DefaultRepository<TEntity extends IEntity> extends BaseRepository<TEntity>{
}
Copy the code
Note the @scope (“prototype”) annotation that indicates that the bean from DefaultRepository is transient and that a new bean is created each time the bean is acquired. Without Scope, spring’s beans are singletons by default. The injected repository instance will be the same instance. Dependency injection @autowired IRepository
studentRepository; And the @autowired IRepository < the Teacher > teacherRepository; , verify that these two repositories are of DefaultRepository type, and verify that operation student does not affect teacher.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {DemoTests.DemoTestsConfiguration.class})
public class DemoTests {
@Autowired
IRepository<Student> studentRepository;
@Autowired
IRepository<Teacher> teacherRepository;
@Test
public void test(){
assertThat(studentIRepository.getClass())
.isEqualTo(DefaultRepository.class);
assertThat(teacherIRepository.getClass())
.isEqualTo(DefaultRepository.class);
studentIRepository.add(new Student());
assertThat(studentIRepository.findAll())
.hasSize(1);
assertThat(teacherIRepository.findAll())
.hasSize(0);
}
@ComponentScan({
"org.example"
})
@Configuration
public static class DemoTestsConfiguration {
}
}
Copy the code
Storage extension
In the previous section, all warehousing operations were defined in BaseRepository, and the warehousing of a single entity needs to be extended if methods not provided in the repository are encountered. Custom repository interface, inherited from IRepository
public interface IStudentRepository extends IRepository<Student>{
Student findById(long id);
}
Copy the code
Implement custom warehouse interface
@Repository public class StudentRepository extends BaseRepository<Student> implements IStudentRepository { @Override public Student findById(long id) { return null; }}Copy the code
Examples of use are as follows
@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {DemoTests.DemoTestsConfiguration.class})
public class DemoTests {
@Autowired
IRepository<Teacher> teacherRepository;
@Autowired
IStudentRepository studentRepository;
@Test
public void repositoryType(){
assertThat(studentRepository.getClass())
.isEqualTo(StudentRepository.class);
assertThat(teacherRepository.getClass())
.isEqualTo(DefaultRepository.class);
}
@ComponentScan({
"org.example"
})
@Configuration
public static class DemoTestsConfiguration {
}
}
Copy the code
conclusion
- With generic dependency injection, you can reduce the number of duplicate code and classes, and in this case, no pair is required
Student
andTeacher
The two entities define the warehouse interface and implementation, with a unified warehouse interface and default implementation doing most of the work.