您的位置:首页 > 编程语言 > Java开发

spring泛型注入

2021-05-09 11:03 92 查看

泛型依赖注入

Spring 4.0版本中更新了很多新功能,其中比较重要的一个就是对带泛型的Bean进行依赖注入的支持。
泛型依赖注入允许我们在使用spring进行依赖注入的同时,利用泛型的优点对代码进行精简,同时在不增加代码的情况下增加代码的复用性。
Spring默认按照字段的类进行依赖注入,而Spring4的新特性就是把泛型的具体类型也作为类的一种分类方法(Qualifier)。

背景

假设有两个实体类

Student
Teacher

@Data
public class Student implements IEntity{
private long id;
}

@Data
public class Teacher implements IEntity{
private long id;
}

实体的存储,是通过

仓储
操作的,一般所有的实体仓储方法都是一致的,只有具体的实体类型不一样,定义仓储接口

public interface IRepository<TEntity extends IEntity>{
void add(TEntity entity);
List<TEntity> findAll();
...
}

定义仓储实现的基类,在本例中,使用List存储

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

}

泛型依赖注入的Bean

BaseRepository
是一个抽象类,不适宜注入到spring中,定义一个可以注入的bean

@Repository()
@Scope("prototype")
public class DefaultRepository<TEntity extends IEntity> extends BaseRepository<TEntity>{
}

注意

@Scope("prototype")
注解,表示
DefaultRepository
的bean的作用是瞬态的,每次获取bean时都会创建一个新的bean,如果不添加作用域,默认spring的bean是单例的,这样注入的仓储实例会是同一个实例。
test
中依赖注入
@Autowired    IRepository<Student> studentRepository;
@Autowired    IRepository<Teacher> teacherRepository;
,
验证这两个仓储的类型都是
DefaultRepository
类型,同时验证操作
student
不会影响到
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 {
}

}

仓储扩展

在上一部分,所有的仓储操作,都定义在了

BaseRepository
中,如果遇到了仓储中未提供的方法,则需要对单个实体的仓储进行扩展。
自定义仓储接口,继承自
IRepository<Student>

public interface IStudentRepository extends IRepository<Student>{
Student findById(long id);
}

实现自定义仓储接口

@Repository
public class StudentRepository extends BaseRepository<Student> implements IStudentRepository {
@Override
public Student findById(long id) {
return null;
}
}

使用例子如下

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {DemoTests.DemoTestsConfiguration.class})
public class DemoTests {

@Autowired
IRepository<Teacher> teacherRepository;

@Autowired
IStudentRepository studentRepository;

@Test
public void repositoryType(){

assertThat(studentRepository.ge
56c
tClass())
.isEqualTo(StudentRepository.class);
assertThat(teacherRepository.getClass())
.isEqualTo(DefaultRepository.class);
}

@ComponentScan({
"org.example"
})
@Configuration
public static class DemoTestsConfiguration {
}

}

总结

  1. 使用泛型依赖注入,可以减少重复代码和类的数目,在本例中,无需对
    Student
    Teacher
    两个实体定义仓储接口和实现,使用统一的仓储接口和默认实现即可完成大部分的操作。
  2. 在项目中,我们使用
    mybatis-plus
    做为仓储层操作数据库,对实体的操作,都需要定义一个
    Mapper
    接口和一个
    Service
    接口,如果使用泛型注入,是否可以减少
    Service
    的代码量呢?
  3. 本文中使用的
    @Repository() @Scope("prototype")
    两个注解注册仓储实例的Bean,
    @Scope("prototype")
    注解会导致每个实体的仓储都是瞬态的,如何保持每个实体对应的仓储Bean是同一个实例呢? 下一篇会介绍另外一种注册Bean的方式: spring bean的动态注入

关注我的公众号,一起探索新技术的海洋

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: