Send you the following Java information, the end of the article has the way to get







Now the interview, basically is the interview to build a rocket 🚀, screw the job. They also like to ask about Spring-related information, such as the difference between @Autowired and @Resource. While the devil climbs ten posts, the priest climbs a post. Soon quite a few programmers learned to recite the interview question, so I turned to the question “How is the @Autowired annotation in Spring implemented?” “, “How does @Autowired work?” Wait, reciting the interview questions will give you away. With that in mind, today we tell you the story behind @Autowired!

preface

When using Spring development, there are two main ways to configure, one is the way of XML, the other is the way of Java Config. Spring technology itself is also constantly developing and changing. From the current hot degree of Spring Boot, the application of Java Config is more and more widespread. In the process of using Java Config, we will inevitably deal with a variety of annotations, among which, Probably the most common annotation we use is the @Autowired annotation. The purpose of this annotation is to inject a defined bean for us. So, what other ways can this annotation be used besides the usual attribute injection? How is it implemented at the code level? This is the focus of this article.

@Autowired annotation usage

Before we examine how this annotation is implemented, let’s review the use of the @Autowired annotation.

Apply the @Autowired annotation to the constructor, as shown in the following example

`public class MovieRecommender {` `private final CustomerPreferenceDao customerPreferenceDao; ` `@Autowired` `public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {` `this.customerPreferenceDao = customerPreferenceDao; ` `} ` ` / /... ` ` `}

Apply the @Autowired annotation to the setter method

`public class SimpleMovieLister {` `private MovieFinder movieFinder; ` `@Autowired` `public void setMovieFinder(MovieFinder movieFinder) {` `this.movieFinder = movieFinder; ` `} ` ` / /... ` ` `}

Apply the @Autowired annotation to methods with any name and multiple parameters

`public class MovieRecommender {` `private MovieCatalog movieCatalog; ` `private CustomerPreferenceDao customerPreferenceDao; ` `@Autowired` `public void prepare(MovieCatalog movieCatalog,` `CustomerPreferenceDao customerPreferenceDao) {` `this.movieCatalog = movieCatalog; ` `this.customerPreferenceDao = customerPreferenceDao; ` `} ` ` / /... ` ` `}

You can also apply @Autowired to a field, or mix it with a constructor, as shown in the following example

`public class MovieRecommender {` `private final CustomerPreferenceDao customerPreferenceDao; ` `@Autowired` `private MovieCatalog movieCatalog; ` `@Autowired` `public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {` `this.customerPreferenceDao = customerPreferenceDao; ` `} ` ` / /... ` ` `}

Directly applying to fields is one of the most common ways we use it, but using constructor injection is much better at the code level, for reasons I won’t go into. Comment in the comments section. In addition, there are a few less common ways.

Add the @Autowired annotation to a field or method that requires an array of that type, and Spring searches for all beans from the ApplicationContext that match the specified type, as shown in the following example:

`public class MovieRecommender {` `@Autowired` `private MovieCatalog[] movieCatalogs; ` ` / /... ` ` `}

Arrays can do that. We can do that in a second. What about containers? Yes. Here’s an example of sets and maps:

`public class MovieRecommender {` `private Set<MovieCatalog> movieCatalogs; ` `private Map<String, MovieCatalog> movieCatalogs; ` `@Autowired` `public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {` `this.movieCatalogs = movieCatalogs; ` `}` `@Autowired` `public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {` `this.movieCatalogs = movieCatalogs; ` `} ` ` / /... ` ` `}

These are the main ways in which @Autowired annotations can be used. If you are a regular Spring user, you should be familiar with some of the most common ones.

What exactly does the @Autowired annotation do

@Autowired is an annotation that we use a lot, and now, the question I want to ask is, what does it actually do?

First, we look at the scope of the annotation, which is in fact an annotation that belongs to Spring’s container configuration, along with @Required, @Primary, @Qualifier, and so on. So the @Autowired annotation is an annotation used for container configuration.

Secondly, we can take it literally. The @autowire annotation is derived from the English word autowire, which means automatic assembly. What does automatic assembly mean? The original meaning of the term refers to some industrial machine that replaces human beings and automates some assembly or other tasks that need to be done. In the Spring world, autowiring refers to the use of beans in the Spring container that are automatically assembled with the class that needs the bean.

Therefore, my personal definition of the use of this annotation is to automatically assemble the beans in the Spring container with the classes we need the beans to work with.

Next, let’s take a look at what’s going on behind this annotation.

How is the @Autowired annotation implemented

In fact, to answer this question you must first understand how Java supports such a feature as annotations.

The core technology of Java’s annotation implementation is reflection, so let’s see how it works by taking a few examples and implementing an annotation ourselves.

The example annotation @Override

The @Override annotation is defined as follows:

`@Target(ElementType.METHOD)`
`@Retention(RetentionPolicy.SOURCE)`
`public @interface Override {`
`}`

The @Override annotation uses the official Java provided annotations and does not have any implementation logic in its definition. Note that almost all annotations are like this: “Annotations can only be considered metadata; they do not contain any business logic.” “An annotation is more like a label, a statement, and the place where it appears to be annotated will have a certain logic.”

The question then arises: the annotation itself contains no logic, so how does the annotation function? The answer must be that this annotation has been implemented somewhere else. In the case of the @Override annotation, its function is to Override a method, and its implementer is the JVM, the Java Virtual Machine, which implements this function at the bytecode level.

However, the implementation of the virtual machine is out of the developer’s control and cannot be used for custom annotations. So, if we want to define a unique annotation ourselves, we need to write our own implementation logic for the annotation, “in other words, we need to implement the functionality of our own annotation specific logic”.

Implement an annotation yourself

There are some basic knowledge we need to know before we write annotations, that is we need to write annotations in Java first, Java supports this feature in JDK5, “and in the java.lang. Annotation package provides four annotations, only for annotation use”, They are:

annotations

role

“@ Documented”

Indicates whether to add annotations to a Java Doc

“@ Retention”

Defines how long an annotation should be retained, known as a valid period. There are several strategies:

“RetentionPolicy.source” – discarded at compile time. After compilation, these comments have no meaning, so they are not written to bytecode. Example @Override, @SuppressWarnings “RetentionPolicy.class” – discarded during CLASS loading. Useful for bytecode level post processing. Somewhat surprisingly, this is the default. “RetentionPolicy.Runtime” – Don’t throw it away. Comments should be reflected at run time. This is what we typically use to customize annotations.

“@ Target”

Specifies where annotations can be placed. If not specified, annotations can be placed anywhere. If we only want a few of them, we need to define the corresponding ones.

Here are the eight properties:

ElementType.type (Class, Interface, Enumeration)

ElementType.field (instance variable)

ElementType.METHOD

ElementType.PARAMETER

ElementType.CONSTRUCTOR

ElementType.LOCAL\_VARIABLE

ANNOTATION\_TYPE (on another ANNOTATION)

ElementType.package (remember package-info.java)

“@ Inherited”

Controls whether annotations affect subclasses.

Let’s start implementing an annotation that only supports primitives, strings, and enumerations. All attributes of an annotation are defined as methods and can also provide default values. Let’s start by implementing a simple annotation.

`import java.lang.annotation.ElementType; ` `import java.lang.annotation.Retention; ` `import java.lang.annotation.RetentionPolicy; ` `import java.lang.annotation.Target; ` `@Target(ElementType.METHOD)` `@Retention(RetentionPolicy.RUNTIME)` `public @interface SimpleAnnotation {` `String value(); ` ` `}

The annotation defines only one character pass. The target annotation object is the method, and the retention policy is at run time. Let’s define a method to use this annotation:

`public class UseAnnotation {` `@SimpleAnnotation("testStringValue")` `public void testMethod(){` `//do something here` `} ` ` `}

So we’re using this annotation here, and we’re assigning the string to testStringValue, and here we are, defining an annotation and using it, and we’re done.

Simple can’t believe it. However, if we think carefully, although we wrote a note and used it, but it did not produce any effect ah. It doesn’t have any effect on our method. Yes, it is right now, and the reason is because of the point we made earlier, we haven’t implemented the logic for this annotation, so let’s implement the logic for this annotation.

How do you do that? We might as well think for ourselves. First of all, I want to give the method or field implementation that annotates this annotation. We need to know which methods and fields use this annotation, so it’s easy to think that reflection will be used. Second, we use reflection, we use reflection to get to the target, we have to implement a logic for it, the logic is outside of the logic of the method itself, which again reminds us of proxies, AOP, etc., we are essentially making an enhancement to these methods. In fact, the realization of the main borrowing logic is probably this train of thought. The general steps are as follows:

  1. Get a Class object of a Class using reflection
  2. This class object can be used to retrieve each of its methods, fields, etc
  3. Classes like Method, Field, and so on provide methods similar to getAnnotation to get all the annotations for a single Field
  4. Once we have the annotation, we can determine if the annotation is the one we want to implement, and if so, implement the annotation logic

Now let’s implement the logic. The code is as follows:

`private static void annotationLogic() {` `Class useAnnotationClass = UseAnnotation.class; ` `for(Method method : useAnnotationClass.getMethods()) {` `SimpleAnnotation simpleAnnotation = (SimpleAnnotation)method.getAnnotation(SimpleAnnotation.class); ` `if(simpleAnnotation ! = null) {` `System.out.println(" Method Name : " + method.getName()); ` `System.out.println(" value : " + simpleAnnotation.value()); ` `System.out.println(" --------------------------- "); ` `} ` `} ` ` `}

The logic we implement here is to print a few sentences. We can’t see from the above implementation logic that using Java reflection we can get all the methods in a class directly, and then get the annotation on the methods, but we can also get the annotation on the fields. We can get almost anything that belongs to a class with the help of reflection.

We are done with a simple annotation. Now let’s step back and look at how the @Autowired annotation is implemented.

The @Autowired annotation implements the logical analysis

Knowing the above knowledge, it is not difficult to think that, although the annotation above is simple, the biggest difference between @Autowired and him should only be in the implementation logic of the annotation, and other steps using reflection to get the annotation should be the same. Let’s take a look at how the @Autowired annotation is defined in Spring’s source code, as follows:

`package org.springframework.beans.factory.annotation; ` `import java.lang.annotation.Documented; ` `import java.lang.annotation.ElementType; ` `import java.lang.annotation.Retention; ` `import java.lang.annotation.RetentionPolicy; ` `import java.lang.annotation.Target; ` `@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})` `@Retention(RetentionPolicy.RUNTIME)` `@Documented` `public @interface Autowired {` `boolean required() default true; ` ` `}

Looking at the code, we can see that the Autowired annotation can be applied to all five types of constructor, normal method, parameter, field, and annotation, and its retention policy is at runtime. Without further ado, let’s look at Spring’s logical implementation of this annotation.

In the Spring of the source code, Autowired annotations in package org. Springframework. Beans. Factory. The annotation, the content of the package is as follows:

After analysis, it is not difficult to find the Spring for the realization of the autowire annotation logic in class: AutowiredAnnotationBeanPostProcessor, has been in the red icon. The core processing code is as follows:

`private InjectionMetadata buildAutowiringMetadata(final Class<? > clazz) {` `LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>(); ` `Class<? > targetClass = clazz; / / need to deal with the target class ` ` do {` ` final LinkedList < InjectionMetadata. InjectedElement > currElements = new LinkedList < > (); /* Gets all fields in the class by reflection, iterates through each field, and iterates through the used annotation for each field using the findAutowiRedAnnotation method, and if modified with Autowired, It returns auotowired relevant properties * / ` ` ReflectionUtils. DoWithLocalFields (targetClass, field -> {` `AnnotationAttributes ann = findAutowiredAnnotation(field); ` `if (ann ! = null) {// Verifies whether the Autowired annotation is used on static methods' 'if (modifier.isstatic (field.getModifiers())) {'' if (Logger.isWarnEnabled ()) {'  `logger.warn("Autowired annotation is not supported on static fields: " + field); ` `}` `return; ' '} Boolean Required = DeterminerEquiredStatus (Ann); ` `currElements.add(new AutowiredFieldElement(field, required)); ` `} ` `}); ' '// Same logic as above, But through the reflection processing method of a class ` ` ReflectionUtils. DoWithLocalMethods (targetClass, method -> {` `Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); ` `if (! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {` `return; ` `}` `AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); ` `if (ann ! = null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {` `if (Modifier.isStatic(method.getModifiers())) {` `if (logger.isWarnEnabled()) {` `logger.warn("Autowired annotation is not supported on static methods: " + method); ` `}` `return; ` `}` `if (method.getParameterCount() == 0) {` `if (logger.isWarnEnabled()) {` `logger.warn("Autowired annotation should  only be used on methods with parameters: " +` `method); ` `}` `}` `boolean required = determineRequiredStatus(ann); ` `PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); ` `currElements.add(new AutowiredMethodElement(method, required, pd)); ` `} ` `}); ' '// There may be more than one annotation modified by @autowements, so they are all added to the currElements container, together with' 'elements. AddAll (0, currElements); ` `targetClass = targetClass.getSuperclass(); ` `}` `while (targetClass ! = null && targetClass ! = Object.class); ` `return new InjectionMetadata(clazz, elements); ` ` `}

The method returns an InjectionMetadata collection that contains all of the Autowire annotations that are added to the source code to understand what it does. This class consists of two parts:

`public InjectionMetadata(Class<? > targetClass, Collection<InjectedElement> elements) {` `this.targetClass = targetClass; ` `this.injectedElements = elements; ` ` `}

The first is the target class we’re working with, and the second is the collection of elements that we get from the above method.

Once we have the target class, and the set of all elements that need to be injected, we can implement the Autowired dependency injection logic by:

`@Override` `public PropertyValues postProcessPropertyValues(` `PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {` `InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); ` `try {` `metadata.inject(bean, beanName, pvs); ` `}` `catch (BeanCreationException ex) {` `throw ex; ` `}` `catch (Throwable ex) {` `throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); ` `}` `return pvs; ` ` `}

It calls the Inject method defined in InjectionMetadata as follows

`public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {` `Collection<InjectedElement> checkedElements = this.checkedElements; ` `Collection<InjectedElement> elementsToIterate =` `(checkedElements ! = null ? checkedElements : this.injectedElements); ` `if (! elementsToIterate.isEmpty()) {` `for (InjectedElement element : elementsToIterate) {` `if (logger.isTraceEnabled()) {` `logger.trace("Processing injected element of bean '" + beanName + "': " + element); ` `}` `element.inject(target, beanName, pvs); ` `} ` `} ` ` `}

The logic is to iterate and then call the inject method. The implementation logic of the inject method is as follows:

`/**` `* Either this or {@link #getResourceToInject} needs to be overridden.` `*/` `protected void inject(Object target,  @Nullable String requestingBeanName, @Nullable PropertyValues pvs)` `throws Throwable {` `if (this.isField) {` `Field field = (Field) this.member; ` `ReflectionUtils.makeAccessible(field); ` `field.set(target, getResourceToInject(target, requestingBeanName)); ` `}` `else {` `if (checkPropertySkipping(pvs)) {` `return; ` `}` `try {` `Method method = (Method) this.member; ` `ReflectionUtils.makeAccessible(method); ` `method.invoke(target, getResourceToInject(target, requestingBeanName)); ` `}` `catch (InvocationTargetException ex) {` `throw ex.getTargetException(); ` `} ` `} ` ` `}

As you can see in the code here, Inject also uses reflection and is still handled into fields and methods. You can call it a “brute force” approach like makeAccessible in the code, but reflection techniques are designed for frameworks and so on, and rightly so.

In the case of a field, you essentially set the value of the field, instantiating and assigning the object, as in the following code:

`@Autowired` `ObjectTest objectTest; `

So what we’re doing here is we’re assigning a value to the objecTest reference.

For a method, the essence is to call the method, so call Method.invoke here.

The parameter of the getResourceToInject method is the name of the bean to be injected, and the function of the method is to retrieve the bean based on its name.

That’s all for analyzing the logic of the @Autowire annotation implementation. If you look at it again in combination with the source code, it will be a little clearer. Here is a diagram of how the Spring container implements the @Autowired auto-injected process:

To sum up: The bean injected with @Autowired is structurally an ordinary member variable for the target class. @Autowired works with Spring to assign the member variable a value through reflection, that is, to the desired instance of the class.

Derivative problems

What is the lifetime of annotations?

The first major difference between the various annotations is whether they are used at compile time and then thrown away (like @Override), or whether they are placed in a compiled class file and made available at run time (like Spring’s @Component). This is determined by the annotation’s “@Retention” policy. If you are writing your own annotation, you need to decide whether it will be useful at run time (possibly for automatic configuration) or only at compile time (for inspection or code generation).

When compiling code with annotations, the compiler sees the annotations just as it sees other modifiers on the source element, such as the access modifier (public/private). When an annotation is encountered, it runs an annotation handler, like a plug-in class, indicating interest in a particular annotation. The annotation handler typically uses the reflection API to examine the elements being compiled, and can simply perform a check on them, modify them, or generate new code to compile. Override is an example; It uses the reflection API to ensure that a match can be found for the method signature in one of the superclasses, and if not, using @Override will result in a compile error.

How is the relationship between the injected bean and the bean that uses it maintained?

Either way, the injected bean is just like a normal object application in the class, which is instantiated by Spring to find a matching bean in the container, instantiate it and inject it into the class. The relationship between them is just a normal relationship where one object holds a reference to another object. It’s just that these objects are beans in Spring.

Why can’t an injected bean be defined as static?

From a design perspective, the use of static fields encourages the use of static methods. The static method is evil. The main purpose of dependency injection is to let the container create objects and wire them for you. Also, it makes testing easier.

Once you start using static methods, you no longer need to create instances of objects, and testing becomes more difficult. Similarly, you cannot create multiple instances of a given class, each injecting a different dependency (because the field is implicitly shared and global state is created).

Static variables are not properties of Object, but properties of Class. Spring’s Autowire is done on objects, which keeps the design clean. In Spring we can also define bean objects as singletons, which can functionally achieve the same purpose as static definitions.

But on a purely technical level, here’s what we can do:

The @Autowired can be used with a setter method, which can then be used to modify the value of a static field. However, this practice is highly discouraged.