I.范型依赖注入

泛型依赖注入(Generic Dependency Injection)是 Spring 4.0 开始有的新特性,可以为子类注入子类对应的泛型类型的成员变量的引用。

什么叫做泛型依赖注入呢,就是说我定义了一个泛型类 A, A 依赖于另一个泛型类 B, 那么, A 和 B 的具体子类也会被 Spring 对应的进行自动管理装配。

下面用讲个示例,UML 图如下:

generic_injection

如图所示, BaseService<T> 依赖于类 BaseRepository<T>, 那么让 Spring 来装配这两个类; 然后它们的具体实现类分别是 UseServiceUserRepository, 具体类型由泛型 T 变成了 User, 那么, Spring 也会自动去装配 UserServiceUserRepository 之间的关联关系,也就是说,IOC 容器会把 UserRepository 这个 Bean对应的装配到 UserService 中去。

下面用代码来具体演示:

先创建一个 User 实体类:

package org.lovian.spring.bean.generic.di;

/**
 * Author: PENG Zhengshuai
 * Date: 4/26/18
 * lovian.org
 */
public class User {
    private String userName;
    private String passWord;
}

创建 BaseRepository 类:

package org.lovian.spring.bean.generic.di;

/**
 * Author: PENG Zhengshuai
 * Date: 4/26/18
 * lovian.org
 */
public class BaseRepository<T> {
}

创建 BaseService 类:

package org.lovian.spring.bean.generic.di;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * Author: PENG Zhengshuai
 * Date: 4/26/18
 * lovian.org
 */
public class BaseService<T> {

    @Autowired
    private BaseRepository<T> baseRepository;

    public void add(){
        System.out.println("add..");
        System.out.println(baseRepository.getClass());
    }
}

这里可以看到,使用了 @Autowired 注解,去给 BaseService 类中装配一个 BaseRepository的实例,然后我们在 BaseService 类中的 add 方法里,去打印实际装配到 BaseService 中的 BaseRepository 类的类型

然后根据 UML 图示,我们去分别创建两个类的子类:

UserRepository,继承 BaseRepository, 使用 @Repository 进行标注,让 IOC 容器进行管理, 会生成一个 userRepository 的 bean:

package org.lovian.spring.bean.generic.di;

import org.springframework.stereotype.Repository;

/**
 * Author: PENG Zhengshuai
 * Date: 4/26/18
 * lovian.org
 */

@Repository
public class UserRepository extends BaseRepository<User> {
}

然后是 UserService 类, 继承 BaseService 类,使用 @Service 进行标注, 让 IOC 容器进行管理, 会生成一个 userService 的bean:

package org.lovian.spring.bean.generic.di;

import org.springframework.stereotype.Service;

/**
 * Author: PENG Zhengshuai
 * Date: 4/26/18
 * lovian.org
 */

@Service
public class UserService extends BaseService<User> {
}

实际上此时,IOC 容器在扫描组件的时候,得到的应该是 userServiceuserRepository 两个 bean, 分别继承与 BaseServiceBaseRepository。但是现在 BaseService 作为父类,私有成员变量是 baseRepository,在 add() 方法中被调用,如果我们从 userService 这个对象中去调用 add() 方法时, 打印出的类型是 BaseService 还是 UserService 呢?

创建一个 xml 配置文件,扫描包中的组件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.lovian.spring.bean.generic.di"/>
</beans>

然后我们测试一下:

package org.lovian.spring.demo;

import org.lovian.spring.bean.generic.di.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Author: PENG Zhengshuai
 * Date: 4/26/18
 * lovian.org
 */
public class GenericDiDemo {
    public static void main(String[] args) {
        ApplicationContext actx = new ClassPathXmlApplicationContext("config/generic_di_beans.xml");
        UserService userService = (UserService) actx.getBean("userService");
        userService.add();
    }
}

得到的打印结果如下:

add..
class org.lovian.spring.bean.generic.di.UserRepository

从结果中可以看到,实际上打印出的是 UserRepository 这个类。这就说明了, IOC 容器,给 userService 自动装配了 userRepository,这就是泛型依赖注入的特性


Share this on