preface
- Based on the previous articleFind out from a source code perspective why the Spring-@Autowired annotation cannot rely on static variables to be injectedI think it is necessary to summarize the spring
@Autowired
The principle of annotations. I have been thinking that when I have not read spring source code@Autowired
The dependency injection mode ofbyTypeIt was not until I read the source code that I broke the myth!
The basics of Spring dependency injection types
-
As mentioned in the previous blog post, Spring’s dependency injection includes the following aspects:
Common dependency injection types The value of the corresponding note AbstractBeanDefinition.AUTOWIRE_NO 0 The automatic assembly function is disabled AbstractBeanDefinition.AUTOWIRE_BY_NAME 1 Auto-assemble by variable name AbstractBeanDefinition.AUTOWIRE_BY_TYPE 2 Automatic assembly according to type AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR 3 Automatic assembly according to construction method AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT Just ignore… The source code indicates that it was deprecated after Spring 3.0 (see the source code below), so I won’t list how it works here (In fact, I don’t know…) -
Spring 3.0 deprecated AutowireCapableBeanFactory AUTOWIRE_AUTODETECT source code
/** * Constant that indicates determining an appropriate autowire strategy * through introspection of the bean class. * @see #setAutowireMode * @deprecatedAs of Spring 3.0: If you are using mixed autowiring strategies, * use annotation-based autowiring for clearer demarcation of autowiring needs. */ @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; Copy the code
How to determine the dependency injection type of a bean
- The steps are as follows:
- First: get the corresponding bean
BeanDefinition
Object (which can be accessed via a post-processor (eg:BeanFactoryPostProcessor) gets the bean factory, which in turn gets the beanDefinition. - Second: strong transition to GenericBeanDefinition
- Third: Call
getResolvedAutowireMode()
methods
- First: get the corresponding bean
- Or simply do breakpoint debugging in the populateBean() method. I’m going to do breakpoint debugging here.
Iii. Project testing
3.1 Project Preview
- AppConfig.java
@Configuration @ComponentScan("com.eugene.sumarry.csdn.autowired") public class AppConfig {}Copy the code
- Entry.java
public class Entry { public static void main(String[] args) { AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(AppConfig.class); System.out.println(context.getBean(UserService.class)); }}Copy the code
- UserService.java
@Service public class UserService { @Autowired private UserDao userDao; @Override public String toString(a) { return "UserService{" + "userDao=" + userDao + '} '; }}Copy the code
- UserDao.java
@Repository public class UserDao {}Copy the code
3.2 Running Tests
Spring has two places to autowage: constructor autowage and populateBean autowage. We summarize this with the @Autowired annotation, ignoring the constructor part. Next, we run the main method directly and navigate to the key parts of the populateBean method
- Conditional breakpoint debugging:As you can see from the above figure, the dependency injection property obtained from beanDefinition is
0
, its value can be seen from the above table:AbstractBeanDefinition.AUTOWIRE_NOIn fact, we can do it inAbstractBeanDefinitionClass viewautowireMode
Property, which defaults to:AUTOWIRE_NO, as shown in the figure:
GetResolvedAutowireMode () = getResolvedAutowireMode Java /** * Return the resolved autowire code * (resolving AUTOWIRE_AUTODETECT to AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE). * @see #AUTOWIRE_AUTODETECT * @see #AUTOWIRE_CONSTRUCTOR * @see #AUTOWIRE_BY_TYPE */ public int getResolvedAutowireMode() { // * * * * * * * * * * * * * look here * * * * * * * * * * * * * * / / to the above said autowireMode attribute, the default value is / / AUTOWIRE_NO, Else return if (this.autowireMode == AUTOWIRE_AUTODETECT) {Constructor
[] constructors = getBeanClass().getConstructors(); for (Constructor
constructor : constructors) { if (constructor.getParameterCount() == 0) { return AUTOWIRE_BY_TYPE; } } return AUTOWIRE_CONSTRUCTOR; } else { return this.autowireMode; }} The @autowired annotation is not used for dependency injection by byType, so how does it work? This is in conjunction with the previous article: finding out from a source code perspective why the Spring-@Autowired annotation can’t rely on static variables to be injected. In the spring, the function of the @autowired annotation is through a rear called AutowiredAnnotationBeanPostProcessor processor to process. The identity of the article is it MergedBeanDefinitionPostProcessors (is to the current class and its parent class (does not contain Object class) all contain the @autowired annotation fields and methods, in the form of InjectionMetadata Object stored in the in JectionMetadataCache property). We didn’t summarize the dependency injection logic for @AutoWired annotations in the previous article, so let’s fix it now.
Fourth, AutowiredAnnotationBeanPostProcessor InstantiationAwareBeanPostProcessor identity
- Yes, you read it right. NowAutowiredAnnotationBeanPostProcessorIs another identity. We go back to
populateBean
Method, continue debugging the code as shown below:
At this point we follow the break point and enterAutowiredAnnotationBeanPostProcessorthepostProcessPropertyValuesMethod, as shown in the figure below:We go ahead and hit the breakpoint at the exit of the method as shown below:To sum up,@Autowired
Dependency injection of annotations is now complete (AutowiredAnnotationBeanPostProcessor when dealing with dependency injection, to obtain from the bean factory, the first is based on the type of field to find qualified bean, if get beans have more than one, is to find an @ Primary annotations modified bean, if all have no, This degrades to the @Resource annotation, which looks for beans by field name, or throws an exception finding more than one bean if none is present. Can locate to org. Springframework. Beans. Factory. The annotation. AutowiredAnnotationBeanPostProcessor. AutowiredFieldElement# inject method scan The logic
). Here by the way: I don’t know you seeChapter 4
The following code in the first diagram is missing:java for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; }}}
There is areturn
Keyword, suppose we write an implementationInstantiationAwareBeanPostProcessor
Interface bean, then can not be broken@Autowired
Annotation function? There’s a caveat, of course:Is this bean processing order to write their own in front of AutowiredAnnotationBeanPostProcessor.
After adding the following code to the project,@Autowired
Annotations are no longer useful (When I was testing then place the processor than AutowiredAnnotationBeanPostProcessor executed first. The Spring version is: 5.0.x ) “`java @Component public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { if (beanName.equals("userService")) { return null; } return pvs; }} ' 'of course, in addition to this method, adding the following code can also disable the @autowired annotation function, ```java @Component public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return false; }} the method above uses the following code of the populateBean method: Java if (! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; }}}} ` ` ` careful friend should be able to find that the difference between these two approaches is to implement method is different, but the implementation of the same interface InstantiationAwareBeanPostProcessor * * * *, so, we can draw a conclusion: ` InstantiationAwareBeanPostProcessor ` type of post processor can let spring ` @autowired ` annotations function failure, Concrete embodiment in ` postProcessPropertyValues ` and ` postProcessAfterInstantiation ` method.Copy the code
Five, the summary
- Let’s not say that the @AutoWired annotation is a byType injection. The principle of the @autowired annotation is AutowiredAnnotationBeanPostProcessor this post processor behind silently pay, to find a qualified properties and injection using reflection.
- In addition, we also learned how to use
InstantiationAwareBeanPostProcessor
Post-processor to destroy@Autowired
The function. - I am a slow walker, but I never walk backwards.