preface

Let’s look at some code.

AnnotationConfigApplicationContext annotationConfigApplicationContext =
      new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.scan("org.springframework.test");
for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
   System.out.println(beanDefinitionName);
}
Copy the code

One question about this code is, how does Spring get classes with @Configuration annotations?

Many steps, the first is to get all the class under the specified package, this part is completed by PathMatchingResourcePatternResolver, he is obtained through path matching mode, so he can not only scan the class, also can scan other files, Resource[] is eventually returned.

For example, to get all classes under com.sp.test, including subpackages, you can write this.

PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] resources = pathMatchingResourcePatternResolver.getResources("classpath:com/sp/test/**/*.class");
Copy the code

The first step is to get the list of class files to be scanned. Some of these classes need to be managed by Spring and some don’t, so the second step is to remove the objects that don’t need to be managed and proceed to the next step.

Objects that need to be managed must have some annotations on the class, so what Spring does is find the class with those annotations, and there are three of them by default in Spring, Component, the Jakarta. The annotation. ManagedBean, Jakarta. Inject. Named, and annotations are integrated such as our common Configuration of the Component. Judgment in this section is located in the source ClassPathScanningCandidateComponentProvider# isCandidateComponent.

But the question is, how do I get class with these annotations? You might think of class.forname (), but it doesn’t work, it executes a static block, so you can’t use this.

There is also the ClassLoader, which does not execute static code blocks, but is not used by Spring for performance reasons, or is not justified, because it causes the JVM to load too many classes.

What’s left is a rough parsing of the class structure, which is difficult but efficient, and which Spring uses, and which is partly handled by the ClassReader source code.

Let’s look at an example of ClassReader.

ClassReader classReader = new ClassReader(Files.readAllBytes(Paths.get("/home/HouXinLin/project/Test.class")));
System.out.println(classReader.getClassName());
System.out.println(classReader.getItemCount());
System.out.println(classReader.getSuperName());
Copy the code

Unfortunately, you can’t get any more information directly, except through the Accept method, which parses the class and calls back to the ClassVisitor object, including all of its annotations.

When judging the class with a Component, the Jakarta. The annotation, ManagedBean, Jakarta. Inject. Named after, will enter the Conditional comments, according to the information to determine the object exactly use management, This part is managed by the ConditionEvaluator class. `

@ManagedBean
@Conditional(value = {TestCondition.class})
public class Config {
   public void print(a) {
      System.out.println("test"); }}Copy the code
public class TestCondition implements Condition {
   @Override
   public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
      return false; }}Copy the code

Returning true under matches indicates that the class does not need to be managed.