An instance of a method in Spring that initializes a generic class

  • 2020-05-30 20:17:53
  • OfStack

Let's start with a simple class definition like this for generic types in Java


class Processor<T> {}

If you want to specify a specific type when initializing directly, you can write this


Processor<String> processor = new Processor<>(); //Java 7  Version and above 

Initialization of basic generics by Spring

If we want to initialize the class with the Spring container, for example, add an @Named annotation to the class above


@Named
class Processor<T> {
}

At this point we pass beanFactory.getBean(Processor.class) What kind of an instance do I get? How does Spring know what specific type to specify? Quite simply, any case of uncertainty is Object. So the Processor instance obtained from the container is equivalent to the Processor instance constructed with the following code


Processor processor = new Processor(); // To be more precise  Processor<Object> processor = new Processor<>();

Step 1. What does Spring do with a generic definition that has an upper bound? like


@Named
class Processor<T extends Number> {
}

Similarly, class Processor<T> The equivalent of class Processor<T extends Object> Therefore, Spring will also use the top-level acceptable type if the specific type is not specified. Spring will create the following object for the above code instance


Processor<Number> processor = new Processor<>();

More complicated, the subtype of the generic is still the case for the generic, as shown in the following code

First, a generic interface is defined


public interface Service<T> {
 String process(T t);
}

The Spring container is then asked to initiate the following NumberService instance


@Named
public class NumberService<R extends Number> implements Service<R> {
 
 @Override
 public String process(R number) {
 return "Process Number: " + number; 
 }
}

When initializing an NumberService instance, Spring also takes the topmost acceptable type and initializes it with the following code


NumberService<Number> numberService = new NumberService<>();

Last but not least, generic types and generic types, what about Spring?


@Named
public class Processor<T> {
 
 @Inject
 Private Service<T> service;
}

How does Spring determine the type T above? Because of the Service<T> service The existence of the attribute makes it impossible to imagine that Spring will initialize the Processor instance with the following code


Processor<String> processor = new Processor<>(); //Java 7  Version and above 
0

Instead, the specific type of Processor must be injected Service<T> The specific type of instance is inferred, depending on what exists in the Spring container Service<T> Instance. Let me give you two examples

If there is an initialization in Spring


Processor<String> processor = new Processor<>(); //Java 7  Version and above 
1

So in front Processor<T> The instance is equivalent to


Processor<String> processor = new Processor<>(); //Java 7  Version and above 
2

If it's initialized in Spring Service<T> It's the one up front NumberService<R extends Number> implements Service<R> So the Spring container Processor<T> Instance equivalent


Processor<Number> processor = new Processor<>();
processor.service = new NumberService<Number>();

What if the previous NumberService and StringService are both registered in the Spring container? Spring is also a bit of a dilemma, as it is impossible to determine which instance to use to inject without @Primary class Processor<T>0 Property, similar error occurred


Processor<String> processor = new Processor<>(); //Java 7  Version and above 
4

This is the same error as normal property injection with multiple optional instances.

Conclusion under 1

If Spring does not provide any concrete type when it initializes a generic class, it initializes the instance with the upper bound type

@Named class Processor<T>  ->  new Processor<Object>() @Named class Processor<T extends Number> -> new Processor<Number>();

If the generic type is associated with the specific type of the property being injected, the primary type is inferred from the property type


Processor<String> processor = new Processor<>(); //Java 7  Version and above 
5

At this point, the Spring container exists class StringService implements Service<String> An instance of the property service(StringService 实例) It is inferred that the specific type of Processor is Processor<String>

Of course, this Processor class can also be defined as a bit more complex 1, such as


Processor<String> processor = new Processor<>(); //Java 7  Version and above 
6

About this article's sample code can be reference https: / / github com yabqiu/spring - generic - demo, please run mvn spring - boot: run view the output results to understand how to initialize the Spring generic class instance.

Ok, that's the whole content of this article, I hope the content of this article can help you to learn or use Spring, if you have any questions, you can leave a message to communicate.


Related articles: