美文网首页
spring泛型注入

spring泛型注入

作者: 诸葛_小亮 | 来源:发表于2021-05-09 08:02 被阅读0次

    泛型依赖注入

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

    背景

    假设有两个实体类StudentTeacher

    @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.getClass())
                    .isEqualTo(StudentRepository.class);
            assertThat(teacherRepository.getClass())
                    .isEqualTo(DefaultRepository.class);
        }
    
    
    
        @ComponentScan({
                "org.example"
        })
        @Configuration
        public static class DemoTestsConfiguration {
        }
    
    }
    
    

    总结

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

    相关文章

      网友评论

          本文标题:spring泛型注入

          本文链接:https://www.haomeiwen.com/subject/sjhmdltx.html