欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring中初始化泛型类的方法实例

程序员文章站 2024-03-07 22:24:40
首先来看下在 java 中对于泛型类型,比如这样简单的类定义 class processor {} 如果直接初始化时要指定具体类型的话,我...

首先来看下在 java 中对于泛型类型,比如这样简单的类定义

class processor<t> {}

如果直接初始化时要指定具体类型的话,我们可以这么写

processor<string> processor = new processor<>(); //java 7 及以上版本

spring 对基本泛型的初始化

如果我们要用 spring 容器来初始化这个类,比如给上面那个类加个 @named 注解

@named
class processor<t> {
}

这时候我们通过 beanfactory.getbean(processor.class) 得到的是一个什么样的实例呢?spring 怎么知道要指定什么具体类型呢?很简单,任何不确定的情况都是 object。所以通过容器得到的  processor 实例相当于用下面代码构造出来的

processor processor = new processor(); //更准确来讲是 processor<object> processor = new processor<>();

再进一步,对于有上限约束的泛型定义,spring 才如何应对呢?像

@named
class processor<t extends number> {
}

类似的,class processor<t> 相当于 class processor<t extends object> , 因此 spring 在具体类型未明的情况下也是要用最顶层可接受类型,spring 将会针对上面的代码实例出下面的对象

processor<number> processor = new processor<>();

再复杂一些,泛型的子类型仍然是泛型的情况,如下代码

首先定义了一个泛型接口

public interface service<t> {
 string process(t t);
}

然后要求 spring 容器来初始下面的 numberservice 实例

@named
public class numberservice<r extends number> implements service<r> {
 
 @override
 public string process(r number) {
 return "process number: " + number; 
 }
}

spring 在初始化 numberservice 实例同样是要取用最顶层可接受类型,通过下面的代码来初始化

numberservice<number> numberservice = new numberservice<>();

再终极一些,泛型类型并且类型也是泛型的,spring 该如何拿捏?

@named
public class processor<t> {
 
 @inject
 private service<t> service;
}

此时 spring 该如何确定上面的类型 t 呢?因为有了 service<t> service 属性的存在而不能再笼统的想像 spring 会采用下面的代码来初始化 processor 实例

processor<object> processor = new processor<>();

而是 processor 的具体类型必须通过被注入的 service<t> 实例的具体类型来推断的,这就取决于在 spring 容器中存在什么样的 service<t> 实例。举两个例子

如果 spring 中有初始化

@named
public class stringservice implements service<string> {
 @override
 public string process(string string) {
 return "process string: " + string;
 }
}

那么前面的 processor<t> 实例就相当于

processor<string> processor = new processor<>();
processor.service = new stringservice();

如果 spring 中初始化的 service<t> 是前面那个 numberservice<r extends number> implements service<r> , 那么 spring 容器中的 processor<t> 实例相当于

processor<number> processor = new processor<>();
processor.service = new numberservice<number>();

那如果前面的 numberservice 和 stringservice 同时在 spring 容器中注册了呢?spring 同样要为难了,在没有 @primary 的情况下无法确定使用哪个实例来注入 service<t> service 属性了,出现类似错误

2016-12-09 00:56:50.922 warn 4950 --- [  main] s.c.a.annotationconfigapplicationcontext : exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.unsatisfieddependencyexception: error creating bean with name 'processor': unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.nouniquebeandefinitionexception: no qualifying bean of type 'cc.unmi.service<?>' available: expected single matching bean but found 2: numberservice,stringservice
2016-12-09 00:56:50.941 error 4950 --- [  main] o.s.b.d.loggingfailureanalysisreporter :

***************************
application failed to start
***************************

description:

field service in cc.unmi.processor required a single bean, but 2 were found:
 - numberservice: defined in file [/users/yanbin/workspaces/github/spring-generic-demo/target/classes/cc/unmi/numberservice.class]
 - stringservice: defined in file [/users/yanbin/workspaces/github/spring-generic-demo/target/classes/cc/unmi/stringservice.class]

action:

consider marking one of the beans as @primary, updating the consumer to accept multiple beans, or using @qualifier to identify the bean that should be consumed

这和普通属性的注入时有多个可选实例时是一样的错误。

总结一下

如果 spring 在初始化泛型类时,未提供任何具体类型则会采用最上限的类型来初始化实例

  1. @named class processor<t>  ->  new processor<object>()
  2. @named class processor<t extends number> -> new processor<number>();

如果泛型类型与被注入的属性的具体类型有关联,则由属性类型推断出主类型

@named class processor<t> {
 @inject service<t> service;
}

此时 spring 容器中存在 class stringservice implements service<string> 的实例,则会由属性 service(stringservice 实例) 推断出 processor 的具体类型是 processor<string>

当然这个 processor 类也是可以定义的稍复杂一些,如

@named class processor<t extends number> {
 @inject service<t> service;
}

关于本文的示例代码可参考 https://github.com/yabqiu/spring-generic-demo, 请运行 mvn spring-boot:run 查看输出结果来理解 spring 怎么去初始化泛型类实例的。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用spring能带来一定的帮助,如果有疑问大家可以留言交流。