preface
Source code version:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.28..RELEASE</version>
</dependency>
Copy the code
A look at the spring on how to use ConfigurationClassPostProcessor to parse the configuration file. This basically see AbstractApplicationContext registerBeanPostProcessors method,
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
Copy the code
As you can see from the comments above the method, this method is registered Bean post-processing.
The body of the
The following positioning to PostProcessorRegistrationDelegate registerBeanPostProcessors method directly:
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {/ / factory in type is a collection of beanName BeanPostProcessor String [] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, // Implement PriorityOrdered, Ordered BeanPostProcessors and the rest. Is actually the BeanPostProcessors classification List < BeanPostProcessor > priorityOrderedPostProcessors = new ArrayList < > (); List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); If (pp instanceof MergedBeanDefinitionPostProcessor) {/ / separation to achieve MergedBeanDefinitionPostProcessor again internalPostProcessors.add(pp); }} else if (the beanFactory isTypeMatch (ppName, Ordered. Class)) {/ / separation of Ordered orderedPostProcessorNames. Add (ppName); } else {/ / the rest, the rest of the nonOrderedPostProcessorNames. Add (ppName); }} // First, register the BeanPostProcessors that implement PriorityOrdered. Registration for PriorityOrdered BeanPostProcessors sortPostProcessors (priorityOrderedPostProcessors, the beanFactory); / / sorting registerBeanPostProcessors (the beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement. Ordered BeanPostProcessors List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); / / sorting registerBeanPostProcessors (the beanFactory, orderedPostProcessors); // Now, Register all regular BeanPostProcessors. // Register all regular BeanPostProcessors List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }} / / registered registerBeanPostProcessors (the beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors. Register all conventional BeanPostProcessors (that is, to realize MergedBeanDefinitionPostProcessor BeanPostProcessors) sortPostProcessors(internalPostProcessors, beanFactory); / / sorting registerBeanPostProcessors (the beanFactory, internalPostProcessors); // Re-register the post-processor for detecting inner beans as ApplicationListeners, // moving it to the end of the processor chain (for picking up proxies etc). beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); / / add a ApplicationListenerDetector}Copy the code
The comments are written into the code. This method isn’t too complicated, but basically just one thing: Register BeanPostProcessors. Here is a flow chart of the entire approach:
MergedBeanDefinitionPostProcessor
In the method above, repeatedly appeared MergedBeanDefinitionPostProcessor, take a look at this interface is what; Let’s start with the class comment:
/** * Post-processor callback interface for <i>merged</i> bean definitions at runtime. * {@link BeanPostProcessor} implementations may implement this sub-interface in order * to post-process the merged bean definition (a processed copy Of the original bean * definition) that the Spring {@code BeanFactory} uses to create a bean instance. To merge bean information at run time. * BeanPostProcessor's implementation class implements this subinterface, To Spring The BeanFactory need to merge when creating The bean instance bean information (a The copy of The original bean information processed) * * < p > The {@ # link postProcessMergedBeanDefinition} method may for example introspect * the bean definition in order to prepare some cached metadata before post-processing * actual instances of a bean. It is also allowed to modify the bean definition but * <i>only</i> for definition properties which are actually intended for concurrent * modification. Essentially, this only applies to operations defined on the * {@link RootBeanDefinition} itself but not to the properties of its base Classes. * postProcessMergedBeanDefinition this method can, for example: in order to rear in the actual instantiation of the bean processing before prepare some cache metadata to a custom bean information. * It also allows you to modify the bean definition, but only the definition properties that are actually used for concurrent modification. * Essentially, this applies only to operations defined on the RootBeanDefinition itself, not to the attribute * */ of its base classCopy the code
To sum up, you can modify some of the bean’s attribute information.
In this place actually registerBeanPostProcessors method (spring – the context 5.2.8), On the MergedBeanDefinitionPostProcessor a internalPostProcessors interface implementation class has two, one is AutowiredAnnotationBeanPostProcessor, One is CommonAnnotationBeanPostProcessor, here only wrote AutowiredAnnotationBeanPostProcessor, Actually CommonAnnotationBeanPostProcessor is mainly deal with the following a few, interested can go to see his concrete realization.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceRef;
Copy the code
AutowiredAnnotationBeanPostProcessor
This class is MergedBeanDefinitionPostProcessor implementation class, this class can be seen from the name above do automatic assembly.
A constructor
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.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
Copy the code
The constructor is to add Autowired, Value, and Inject into autowiredAnnotationTypes.
PostProcessMergedBeanDefinition method
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class
beanType, String beanName) {
// Query autowiring metadata
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
// Check the configuration
metadata.checkConfigMembers(beanDefinition);
}
Copy the code
private InjectionMetadata findAutowiringMetadata(String beanName, Class<? > clazz,@Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if(metadata ! =null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
}
Copy the code
The main process of this method is:
- Determine the cache
- lock
- Build a data
- Memory cache
The most important part of this method is the buildAutowiringMetadata method.
private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
if(! AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = newArrayList<>(); Class<? > targetClass = clazz;do {
// Build currElements to store the data that meets the criteria
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// Iterate over the arguments of the current class
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// Find the qualified parameters (that is, the three annotations in the constructor)MergedAnnotation<? > ann = findAutowiredAnnotation(field);if(ann ! =null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// Get the required parameter
boolean required = determineRequiredStatus(ann);
// Join if the conditions are met
currElements.add(newAutowiredFieldElement(field, required)); }});// Iterate over all the methods of the current class
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// Find the method that matches the condition (same as above)
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return; } MergedAnnotation<? > ann = findAutowiredAnnotation(bridgedMethod);if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: "+ method); }}// Get the required parameter
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// Add to currElements
currElements.add(newAutowiredMethodElement(method, required, pd)); }}); elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while(targetClass ! =null&& targetClass ! = Object.class);// Iterate up until the parent class is Object.
return InjectionMetadata.forElements(elements, clazz); / / return
}
Copy the code
This method is mainly the following points:
- Keep going up until the parent class is zero
Object
So far. - Iterates through the class’s parameters and methods to find conditions (by
@Autowired
.@Value
.@Inject
Modifier), and finally put into the collection - Encapsulate the collection and return
privateMergedAnnotation<? > findAutowiredAnnotation(AccessibleObject ao) { MergedAnnotations annotations = MergedAnnotations.from(ao);for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { MergedAnnotation<? > annotation = annotations.get(type);if (annotation.isPresent()) {
returnannotation; }}return null;
}
Copy the code
This method iterates through the autowiredAnnotationTypes to see if the parameter or method is modified by an annotation in the autowiredAnnotationTypes.
Now that you’ve found the parameters and methods decorated with the appropriate annotations using the findAutowiringMetadata method, it’s time to execute the checkConfigMembers method. This method in the org. Springframework. Beans. Factory. The annotation. InjectionMetadata class.
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
for (InjectedElement element : this.injectedElements) {
Member member = element.getMember();
if(! beanDefinition.isExternallyManagedConfigMember(member)) { beanDefinition.registerExternallyManagedConfigMember(member); checkedElements.add(element);if (logger.isTraceEnabled()) {
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]."+ element); }}}this.checkedElements = checkedElements;
}
Copy the code
This method iterates through the data taken from the findAutowiringMetadata method, returns the encapsulated data, and finally puts it into the RootBeanDefinition, or bean definition information.
The last
At this point, the post-processing in Spring is registered, and it’s up to you to see when it’s called.