Antecedents to review

Spring supports BeanPostProcessor (BeanPostProcessor), and uses two methods of BeanPostProcessor: PostProcessBeforeInitialization, postProcessAfterInitialization execution time, no friend can go back and look at. I was going to cover spring autowiring in detail in the last post, but I thought it might be too much, and now that you’ve got the feeling, I’m not going to cover it in the last post because it was too much. All right, let’s get back to the point, and the reason why we didn’t get to the last one is just the length

One, the main reason is that I made a mistake! What did you do wrong?

I took it for granted! Take it for granted that automatic assembly is implemented in the postProcessBeforeInitialization or postProcessAfterInitialization AutowiredAnnotationBeanPostProcessor, We’ll look at AutowiredAnnotationBeanPostProcessor class diagram

It has realized the BeanPostProcessor indirectly, we’ll go to see the two methods (in the superclass InstantiationAwareBeanPostProcessorAdapter)

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 return bean;
}
Copy the code

It does nothing but a simple return bean; It’s a terrible feeling when what you think is true is overturned

So automatic assembly and BeanPostProcessor can not be put together, have to open two separate, we all know: strong twist melon is not sweet!

A simple example of autowiring

Let’s start with a simple autoloader example, complete with spring-boot-BeanPostProcessor

AnimalServiceImpl

@Service
public class AnimalServiceImpl implements IAnimalService {
 @Autowired
 private Dog dog;
 @Resource
 private Cat cat;
 @Inject
 private Pig pig;
 @Override
 public void printName() { System.out.println(dog.getName()); System.out.println(cat.getName()); System.out.println(pig.getName()); }}Copy the code

AnimalTest

@RunWith(SpringRunner.class)
@SpringBootTest(classes={Application.class})
public class AnimalTest {
 @Autowired
 private IAnimalService animalService;
 @Test
 public void test() { animalService.printName(); }}Copy the code

The results

We only registered Dog, Cat, and Pig instances with the Spring container in AnimalConfig, so why can the AnimalServiceImpl instance apply these instances directly? We didn’t manually assign these instances to the AnimalServiceImpl instance. This is exactly what Spring provides for auto-assembly. Although we did not manually assign these instances to the AnimalServiceImpl instance, we noticed that the AnimalServiceImpl attribute instance has some annotations: @autowired, @Resource, @inject, Spring uses these annotations to automatically Inject property instances without requiring manual assignment; So how does Spring implement autowiring? Let’s take a look (note: @Autowired is used as an example)

Automatic assembly source code parsing

AutowiredAnnotationBeanPostProcessor instantiation and registered

Anyway, AutowiredAnnotationBeanPostProcessor ultimately a BeanPostProcessor, The process of instantiation and registration (registering to Spring’s beanFactory) is the same as that of BeanPostProcessor. During spring startup, when the context is refreshed, Invokes the registerBeanPostProcessors (the beanFactory) method completed the BeanPostProcessor instantiation and registration, Subsequent calls again finishBeanFactoryInitialization (the beanFactory) instantiation of lazy loading singleton beans, use the above registration BeanPostProcessor

AutowiredAnnotationBeanPostProcessor constructor is worth a look

public AutowiredAnnotationBeanPostProcessor() {
 this.autowiredAnnotationTypes.add(Autowired.class);
 this.autowiredAnnotationTypes.add(Value.class);
 try {
 this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
 ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
 logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
 }
 catch (ClassNotFoundException ex) {
 // JSR-330 API not available - simply skip.
 }
}
Copy the code

By default, AutowiredAnnotationBeanPostProcessor support @autowired and @ Value, if there is a Java classpath. Inject. Inject (namely javax.mail is introduced. The inject. Jar). So also support @inject annotation, is it a little different from our initial cognition?

Free the supported annotations to the autowiredAnnotationTypes property, which will be used later

Bean instantiation and dependency injection

By default, spring treats beans in the Spring container as non-lazy-init singletons (except for some special beans), which means that they are instantiated one by one during Spring startup and dependency injection is performed on them. Isn’t it great that when we actually use these beans, we just use them without having to instantiate them or inject bean dependencies?

Get ready for peanuts, melon seeds and beer, and the show is about to begin

Let’s find the right entry, then skip the boring foreplay with the image below and jump right into the climax: doCreateBean

The content of doCreateBean is as follows

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
 throws BeanCreationException {
 // Instantiate the bean.
 BeanWrapper instanceWrapper = null;
 if (mbd.isSingleton()) {
 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 }
 if(instanceWrapper == null) {// createBeanInstance instanceWrapper = createBeanInstance(beanName, MBD, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. // Allow post-processors to modify the merged bean definition (mbd.postProcessingLock) {if(! MBD. PostProcessed) {try {/ / / / call MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition method To achieve a AutowiredAnnotationBeanPostProcessor MergedBeanDefinitionPostProcessor, Namely MergedBeanDefinitionPostProcessor MergedBeanDefinitionPostProcessor is called applyMergedBeanDefinitionPostProcessors (MBD, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);
 }
 mbd.postProcessed = true; } // sometimes I cache singletons to be able to resolve circular references // even when triggered by triggered references lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {
 if (logger.isDebugEnabled()) {
 logger.debug("Eagerly caching bean '" + beanName +
 "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; Try {// Populate the bean with dependency injection populateBean(beanName, MBD, instanceWrapper); ExposedObject = initializeBean(beanName, exposedObject, MBD); } catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
 throw (BeanCreationException) ex;
 }
 else {
 throw new BeanCreationException(
 mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); }}if (earlySingletonExposure) {
 Object earlySingletonReference = getSingleton(beanName, false);
 if(earlySingletonReference ! = null) {if (exposedObject == bean) {
 exposedObject = earlySingletonReference;
 }
 else if(! this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {
 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
 actualDependentBeans.add(dependentBean);
 }
 }
 if(! actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +
 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
 "] in its raw version as part of a circular reference, but has eventually been " +
 "wrapped. This means that said other beans do not use the final version of the " +
 "bean. This is often the result of over-eager type matching - consider using " +
 "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
 }
 }
 }
 }
 // Register bean as disposable.
 try {
 registerDisposableBeanIfNecessary(beanName, bean, mbd);
 }
 catch (BeanDefinitionValidationException ex) {
 throw new BeanCreationException(
 mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
 }
 return exposedObject;
}
Copy the code

We focus on the methods and populateBean posProcessMergedBeanDefinition method

posProcessMergedBeanDefinition

You can see that annotations are read on the bean’s field and method and determine if the annotation is in autowiredAnnotationTypes, Encapsulate field as an AutowiredFiledElement and Method as an AutoWiredMethodElement. Set<InjectedElement> checkedElements; Finally the InjectionMetadata object cache to AutowiredAnnotationBeanPostProcessor Map < String, InjectionMetadata> injectionMetadataCache; Basically, find the fields and methods that are decorated by @Autowried (and of course, @Value and @inject), encapsulate them as InjectionMetadata objects and cache them. It’s as simple as that. All non-lazy-loaded beans in Spring go through this creation process, not just the animalServiceImpl bean shown above. Is it easy? Is it full of energy

populateBean

Call AutowiredAnnotationBeanPostProcessor postProcessPropertyValues method, gets the current bean from injectionMetadataCache rely on information, For example, the animalServiceImpl dependencies on Dog, Pig (one might wonder: Cat? Cat is @ the Resource modification, and @ the Resource is not supported by AutowiredAnnotationBeanPostProcessor, follow-up can speak who support), Then inject the dependent beans one by one into the target beans (injecting dog and Pig instances into the animalServiceImpl instance); Where do dependent beans come from? The dependency bean (dog, Pig) is created in the same way as the animalServiceImpl instance is created. The animalServiceImpl instance creates dog and Pig objects during dependency injection, rather than waiting for Spring to instantiate pig and dog beans one by one. Spring caches the created bean and fetches it directly from the cache next time. The image above only demonstrates Field, Method is not too far, not to demonstrate, are implemented by reflection.

conclusion

1. Bean creation and initialization

InstanceWrapper = createBeanInstance(beanName, MBD, args);

(2) applyMergedBeanDefinitionPostProcessors (MBD, beanType, beanName) looking for target bean rely on;

(3) populateBean(beanName, MBD, instanceWrapper) fills the target bean to complete dependency injection; (Loop dependency here, if you are interested, you can think about it by yourself.)

InitializeBean (beanName, exposedObject, MBD) initializes the target bean

2, automatic assembly and automatic configuration

Auto Configuration is generally referred to as @autoWired, which is one of spring’s features, while auto Configuration is @Configuration, which is one of SpringBoot’s features

Spring supports several types of autowiring annotations

@Autowired, @Inject, @Resource, and @Value, the most used is @Autowired (at least I do), @ @ and Inject the Value is also supported by AutowiredAnnotationBeanPostProcessor, And @ Resource is supported by CommonAnnotationBeanPostProcessor (also supports @ PostConstruct, @ PreDestroy annotations etc.)

As for @Value and @autowired, I don’t know if you are clear about the difference between them. @Value >= @Autowired, but in normal applications, @Value is more used to inject configuration values (e.g. @value (“${db.url}”)), while @AutoWired is an injection of the bean object