Spring框架(二) 底层架构核心概念解析-四万字你值得一看

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 上面说到解析为BeanDefintion之后会注册到Spring容器中 , 那么什么是容器? 其实在DefaultListableBeanFactory这个类中就有体现 , 源码中是这样定义的

本篇文章将对Spring底层的一些概念做一些简单的分析 , 也是为了方便后续在阅读源码的时候更加的方便


BeanDefintion

BeanDefintion是一个接口 , 它表示一个Bean的定义 , BeanDefintion存在很多属性来描述一个Bean的特点 , Spring在扫描完需要注册的Bean之后会进行解析 , 而解析的数据就会存入到BeanDefintion

我们在定义Bean的时候可以分为两种方式 :


申明式

申明式定义一个Bean就比如我们用的@Bean , @Component等注解 , 或者是xml标签的形式来定义一个Bean


编程式

编程式就是通过写代码的方式来定义 , 如下

public class MemberService {
  public void test(){
    System.out.println("test方法被调用...");
  }
}

接着我们从Spring获取这个’Bean’ , 看是否能获取到


public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  MemberService memberService = (MemberService) applicationContext.getBean("memberService");
  memberService.test();


运行之后我们回发现报错了 , 报错内容如下 :


org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘memberService’ available

没有找到一个名为memberService的Bean来使用


我们再用编程式的方式定义


public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  // 得到一个BeanDefinition对象
  AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
  // 设置Bean的类型
  beanDefinition.setBeanClass(MemberService.class);
  // 设置Bean的作用域
  beanDefinition.setScope("prototype");
  // 当然光这样申明还是不够的 , 我们需要调用一个函数来把这个beanDefinition注册到容器中 , 在注册的时候我们可以指定一个Bean的名称
  applicationContext.registerBeanDefinition("memberService" , beanDefinition);
  MemberService memberService = (MemberService) applicationContext.getBean("memberService");
  memberService.test();
  }
}

接着运行进行测试 , 会发现这次并没有报错 , 并且也打印出来了 “test方法被调用…”

其实不难理解 , 我们通过注解的方式去定义 , 当Spring扫描完解析的时候 , 他底层也会把解析的结果封装到BeanDefinition, 我们现在不通过注解申明的方式 , 而是直接编程式的把值封装到BeanDefinition中 , 然后注册到Spring容器 , 这样我们就可以使用了


BeanDefinitionReader

现在我们介绍几种BeanDefintion的几种读取器 , 虽然在工作中用的很少 , 但是 , 它也是Spring基础设施中比较重要的一部分


AnnotatedBeanDefinitionReader

可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,如下


public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  // 把某一个类转换为BeanDefinition之后 , 我们也需要将它注册到Spring容器中 , 所以需要传一个ApplicationContext对象
  AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
  // 注册到Spring容器中
  annotatedBeanDefinitionReader.register(MemberService.class);
  MemberService memberService = (MemberService) applicationContext.getBean("memberService");
  memberService.test();
  }
}

运行测试发现控制台打印 " test方法被调用…" , 我们可以简单看一下register()方法

public void register(Class<?>... componentClasses) {
  for (Class<?> componentClass : componentClasses) {
    registerBean(componentClass);
  }
  }


public void registerBean(Class<?> beanClass) {
  doRegisterBean(beanClass, null, null, null, null);
  }

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
    @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
    @Nullable BeanDefinitionCustomizer[] customizers) {
  AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
  if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    return;
  }
  abd.setInstanceSupplier(supplier);
  // 解析@Scope注解的结果为ScopeMetadata
  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
  // 将类的作用域添加到数据结构中
  abd.setScope(scopeMetadata.getScopeName());
  String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
  AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
  if (qualifiers != null) {
    for (Class<? extends Annotation> qualifier : qualifiers) {
    if (Primary.class == qualifier) {
      abd.setPrimary(true);
    }
    else if (Lazy.class == qualifier) {
      abd.setLazyInit(true);
    }
    else {
      abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    }
    }
  }
  if (customizers != null) {
    for (BeanDefinitionCustomizer customizer : customizers) {
    customizer.customize(abd);
    }
  }
  BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
  definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }

我们看一下processCommonDefinitionAnnotations()方法


public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
  processCommonDefinitionAnnotations(abd, abd.getMetadata());
  }
// 处理@Lazy、@Primary、@DependsOn、@Role、@Description
  static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
  AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
  if (lazy != null) {
    abd.setLazyInit(lazy.getBoolean("value"));
  }
  else if (abd.getMetadata() != metadata) {
    lazy = attributesFor(abd.getMetadata(), Lazy.class);
    if (lazy != null) {
    abd.setLazyInit(lazy.getBoolean("value"));
    }
  }
  if (metadata.isAnnotated(Primary.class.getName())) {
    abd.setPrimary(true);
  }
  AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
  if (dependsOn != null) {
    abd.setDependsOn(dependsOn.getStringArray("value"));
  }
  AnnotationAttributes role = attributesFor(metadata, Role.class);
  if (role != null) {
    abd.setRole(role.getNumber("value").intValue());
  }
  AnnotationAttributes description = attributesFor(metadata, Description.class);
  if (description != null) {
    abd.setDescription(description.getString("value"));
  }
  }

可以看到 , 他底层的逻辑代码和我们刚刚用编程式定义的方式差不多 , 也是创建一个BeanDefintion对象 , 然后解析注解并设置BeanDefintion的值 , 那么这个AnnotatedBeanDefinitionReader读取器在什么时候用的呢?其实是在创建AnnotationConfigApplicationContext容器对象时候用的 , 我们点进去看一下它的构造方法

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
  // 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
  this();
  // 注册bean配置类
  register(componentClasses);
  // 刷新上下文
  refresh();
  }


然后看this()方法

public AnnotationConfigApplicationContext() {
  StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
  // 额外会创建StandardEnvironment
  this.reader = new AnnotatedBeanDefinitionReader(this);
  createAnnotatedBeanDefReader.end();
  this.scanner = new ClassPathBeanDefinitionScanner(this);

我们就可以看到它构造了一个AnnotatedBeanDefinitionReader对象 , 其实Spring容器本身也有register()方法


AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  applicationContext.register();


其实它们使用的是同一个方法 , 看一看applicationContext.register()方法的源码


@Override
  public void register(Class<?>... componentClasses) {
  Assert.notEmpty(componentClasses, "At least one component class must be specified");
  StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
    .tag("classes", () -> Arrays.toString(componentClasses));
  this.reader.register(componentClasses);
  registerComponentClass.end();
  }


public void register(Class<?>... componentClasses) {
  for (Class<?> componentClass : componentClasses) {
    registerBean(componentClass);
  }
  }


public void registerBean(Class<?> beanClass) {
  doRegisterBean(beanClass, null, null, null, null);
  }


可以看到, 它们最终调用的都是doRegisterBean()方法 , 都是会把传入的类转换为一个BeanDefintion


XmlBeanDefinitionReader

既然有解析类的读取器的 , 那么也就应该有解析xml标签的 , 它就是XmlBeanDefinitionReader , 如下

首先定义一个xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
   https://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
    >
  <bean id="member" class="com.lyh.service.MemberService"/>
</beans

然后我们通过如下的方式来获取



public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext); 
  xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
  MemberService memberService = (MemberService) applicationContext.getBean("memberService");
  memberService.test();
  }
}

ClassPathBeanDefinitionScanner

前面介绍的两个是读取器 , 现在来介绍一个BeanDefinition扫描器 , 读取器 , 读取类以及xml文件然后解析成为一个BeanDefintion , 那么扫描器, 那么就是读取某个包路径下的类 , 然后进行解析 ,比如,扫描到的类上如果存在@Component 注解,那么就会把这个类解析为一个BeanDefinition , 如下


申明一个ScannerService来测试


public class ScannerService {
  public void test(){
  System.out.println("执行了ScannerService.test()方法");
  }
}

取消AppConfig.class这个入参


public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
  scannerService.test();
  }
}

这样运行肯定是报错的 , 即使在ScannerService类加上了@Component注解 , 因为这里没有传配置文件进去 , 所以构造的是一个空的Spring容器

报错信息如下:


Exception in thread “main” java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@433c675d has not been refreshed yet
在这里插入代码片

它提示我们这个容器还没有刷新一下 , 加一行代码来刷新一下

public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  applicationContext.refresh();
  ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
  scannerService.test();
  }
}

发现刷新之后还是报错 , 报错信息如下 :


Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘scannerService’ available

没有一个名为scannerService的Bean用来使用


我们现在用这个扫描器试一下


public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);
  scanner.scan("com.lyh");
  ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
  scannerService.test();
  }
}

发现控制台打印了 “执行了ScannerService.test()方法” , 也就是说这个扫描器生效了 , 它扫描到了ScannerService并且这个类加了@Component , 就表示这个类需要注册为一个Bean , 就会把这个类解析并放入Spring容器 , 其实比较细心的话就可以发现ClassPathBeanDefinitionScanner这个类是在之前申明AnnotatedBeanDefinitionReader读取器的时候也申明了


public AnnotationConfigApplicationContext() {
  StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
  // 额外会创建StandardEnvironment
  this.reader = new AnnotatedBeanDefinitionReader(this);
  createAnnotatedBeanDefReader.end();
  this.scanner = new ClassPathBeanDefinitionScanner(this);
  }

所以这里我们就知道了 , 我们的Spring容器它既可以去注册某一个类成为Bean ,也可以去扫描 , 当然它的内部会进行扫描 , 我们自己触发也是可以的 , 所以AnnotationConfigApplicationContext 也是有这两个功能的 , 一个是直接注册 , 一个是扫描


AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  // 需要传入一个包路径
  applicationContext.scan();

BeanDefinition子类

上面我们说到 , BeanDefinition是一个接口 , 那么重要的实现类有这么三个 :

1.GenericBeanDefinition

2.AnnotatedGenericBeanDefinition

3.ScannedGenericBeanDefinition


它们之前的父子关系是这样的

c224aca74fdbac71696ca0ca688e55cf_a2f582f7810f4f86beb5518716aad6e4.png


AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition的区别

先来看ScannedGenericBeanDefinition , 它表示是扫描出来的BeanDefinition的类型

我们来看源码 , 从刚刚scan()的源码进去

scanner.scan(“com.lyh”);
  public int scan(String... basePackages) {
  int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
  doScan(basePackages);
  // Register annotation config processors, if necessary.
  if (this.includeAnnotationConfig) {
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  }
  return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
  }

再来看doScan()


protected Set doScan(String... basePackages) {
  Assert.notEmpty(basePackages, "At least one base package must be specified");
  Set beanDefinitions = new LinkedHashSet<>();
  for (String basePackage : basePackages) {
    Set candidates = findCandidateComponents(basePackage);
    for (BeanDefinition candidate : candidates) {
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    candidate.setScope(scopeMetadata.getScopeName());
    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    if (candidate instanceof AbstractBeanDefinition) {
      postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    }
    if (candidate instanceof AnnotatedBeanDefinition) {
      // 解析@Lazy、@Primary、@DependsOn、@Role、@Description
      AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    }
    // 检查Spring容器中是否已经存在该beanName
    if (checkCandidate(beanName, candidate)) {
      BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
      definitionHolder =
        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
      beanDefinitions.add(definitionHolder);
      // 注册
      registerBeanDefinition(definitionHolder, this.registry);
    }
    }
  }
  return beanDefinitions;
  }

再来看findCandidateComponents()


public Set findCandidateComponents(String basePackage) {
  if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
    return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
  }
  else {
    return scanCandidateComponents(basePackage);
  }
  }

再来看scanCandidateComponents()


private Set scanCandidateComponents(String basePackage) {
  Set candidates = new LinkedHashSet<>();
  try {
    // 获取basePackage下所有的文件资源
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
      resolveBasePackage(basePackage) + '/' + this.resourcePattern;
    Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
    boolean traceEnabled = logger.isTraceEnabled();
    boolean debugEnabled = logger.isDebugEnabled();
    for (Resource resource : resources) {
    if (traceEnabled) {
      logger.trace("Scanning " + resource);
    }
    if (resource.isReadable()) {
      try {
      MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
      // excludeFilters、includeFilters判断
      if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断
        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
        sbd.setSource(resource);
        if (isCandidateComponent(sbd)) {
        if (debugEnabled) {
          logger.debug("Identified candidate component class: " + resource);
        }
        candidates.add(sbd);
        }
        else {
        if (debugEnabled) {
          logger.debug("Ignored because not a concrete top-level class: " + resource);
        }
        }
      }
      else {
        if (traceEnabled) {
        logger.trace("Ignored because not matching any filter: " + resource);
        }
      }
      }
      catch (Throwable ex) {
      throw new BeanDefinitionStoreException(
        "Failed to read candidate component class: " + resource, ex);
      }
    }
    else {
      if (traceEnabled) {
      logger.trace("Ignored because not readable: " + resource);
      }
    }
    }
  }
  catch (IOException ex) {
    throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
  }
  return candidates;
  }

我们可以看到这样一行代码 :

ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

就表示扫描出来的BeanDefinition类型是ScannedGenericBeanDefinition


再来看AnnotatedGenericBeanDefinition

我们还是进入到AnnotationConfigApplicationContext的构造方法

public AnnotationConfigApplicationContext(Class... componentClasses) {
  // 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
  this();
  // 注册bean配置类
  register(componentClasses);
  // 刷新上下文
  refresh();
  }

看register()方法


@Override
  public void register(Class... componentClasses) {
  Assert.notEmpty(componentClasses, "At least one component class must be specified");
  StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
    .tag("classes", () -> Arrays.toString(componentClasses));
  this.reader.register(componentClasses);
  registerComponentClass.end();
  }


再看 this.reader.register();

public void register(Class... componentClasses) {
  for (Class componentClass : componentClasses) {
    registerBean(componentClass);
  }
  }


再看registerBean()

public void registerBean(Class beanClass) {
  doRegisterBean(beanClass, null, null, null, null);
  }


再看doRegisterBean()


private  void doRegisterBean(Class beanClass, @Nullable String name,
    @Nullable Class[] qualifiers, @Nullable Supplier supplier,
    @Nullable BeanDefinitionCustomizer[] customizers) {
  AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
  if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    return;
  }
  abd.setInstanceSupplier(supplier);
  // 解析@Scope注解的结果为ScopeMetadata
  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
  // 将类的作用域添加到数据结构中
  abd.setScope(scopeMetadata.getScopeName());
  String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
  AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
  if (qualifiers != null) {
    for (Class qualifier : qualifiers) {
    if (Primary.class == qualifier) {
      abd.setPrimary(true);
    }
    else if (Lazy.class == qualifier) {
      abd.setLazyInit(true);
    }
    else {
      abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    }
    }
  }
  if (customizers != null) {
    for (BeanDefinitionCustomizer customizer : customizers) {
    customizer.customize(abd);
    }
  }
  BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
  definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }

我们可以看到这样一行代码 :

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

就表示扫描并解析到的BeanDefinition类型是AnnotatedGenericBeanDefinition类型


我们简单理解 , 一个扫描器 ,一个读取器 , 最终得到的都是一个BeanDefinition对象 , 但是他是进行区分的


当然还有比较重要的两个BeanDefinition子类

1.RootBeanDefinition

2.ChildBeanDefinition

他们的父子关系是这样的


d43f5a7db30f0bbafae9f5ee5dce46d3_d5eeb600e46840669b69295dbf90224f.png

ChildBeanDefinition和RootBeanDefinition的区别

ChildBeanDefinition基本从Spring2.5开始就很少用了 , 都是用GenericBeanDefinition来代替

RootBeanDefinition 它是常用的 , 而且用的比较多 , 因为RootBeanDefinition和Bean的生命周期有关 , 所以我们后面来讲 , 它是和合并beanDefinition有关的 , 目前为止有这个合并beanDefinition的概念即可


BeanFactory

BeanFactory它是一个接口 , 表示Bean工厂 , 它的作用就是用来创建Bean对象的 , 我们一般常用的Bean工厂是ApplicationContext , 为什么说ApplicationContext 也是Bean工厂呢?

源码中它的类是这样定义的

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
  MessageSource, ApplicationEventPublisher, ResourcePatternResolver {


而ListableBeanFactory, HierarchicalBeanFactory都继承了BeanFactory , 所以说ApplicationContext它其实就是一个Bean工厂 , 所以ApplicationContext 他肯定拥有BeanDactory的功能 , 那么ApplicationContext和BeanFactory有什么区别呢?


其实从源码我们不难看出 , 它还继承了一些其他的接口, 比如ApplicationEventPublisher事件发布器 ,

EnvironmentCapable获取环境变量等 , 这个是BeanFactory所没有的 ,它的功能也就比BeanFactory更强大一点


DefaultListableBeanFactory

上面说到解析为BeanDefintion之后会注册到Spring容器中 , 那么什么是容器? 其实在DefaultListableBeanFactory这个类中就有体现 , 源码中是这样定义的


/** Map of bean definition objects, keyed by bean name. */
  private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);


其实说白了它就是一个map , key就是Bean的名称 , value就是解析出来的Map ,当然 , 我们也可以把Spring容器理解为单例池 , 单例池就是一个Map , 它存的就是所有的单例Bean , key也是Bean的名称 , value是Bean的实例 , 源码是这样定义的


// 单例池
  private final Map singletonObjects = new ConcurrentHashMap<>(256);


是在我们在使用AnnotationConfigApplicationContext的时候就有用到这个类 , 我们需要知道的是 , 在加载构造方法之前 , 它会先加载父类的构造方法 , 而在父类的构造方法中就初始化一个DefaultListableBeanFactory , 其实我们的getBean()功能就是DefaultListableBeanFactory 实现的


public GenericApplicationContext() {
  this.beanFactory = new DefaultListableBeanFactory();
  }


DefaultListableBeanFactory的功能是非常强大的 , 支持很多功能,可以通过查看DefaultListableBeanFactory的类继承实现结构来看


da9ab00a30769fd28789620e11d39288_8561de314e5344789c2c7833c9f7b22f.png

Aliasregistry

Aliasregistry ,通过类图我们可以看到DefaultListableBeanFactory也是实现了Aliasregistry接口的 ,

而Aliasregistry接口提供的就是别名注册的功能 , 如果没有实现这个接口 , 就表示一个Bean只能有一个名称 ,但是实现了这个接口 , 我们就可以给这个Bean起一个别名


singletionBeanisgtry

singletionBeanisgtry , 它提供的就是单例Bean的功能


BeanDinfinitionRegistry

BeanDinfinitionRegistry , 实现了这个接口就可以有BeanDinfinition注册的功能


HierarchicalBeanFactory

HierarchicalBeanFactory , 它可以获取父Bean工厂 , 如果实现了这个接口 , 就表示这个Bean工厂是支持父子Bean工厂的 , 也就是说如果有两个Bean工厂 , 它们是父子Bean工厂 , 如果子Bean工厂get不到Bean , 那么我们就会从父工厂去get


ListableBeanFactory

ListableBeanFactory , 它可以根据Bean的名称判断是否包含BeanDefinition , 以及获取BeanDefinition的数量 , 获取所有BeanDefinition的名称也就是Bean的名称 , 比如还可以根据指定类型获取Bean的名称 , 其实这个类提供的也就是一个展示的功能 , Bean的名称 , 数量…等


AutowireCapableBeanFactory

AutowireCapableBeanFactor,是直接继承了BeanFactory,在BeanFactory的基础上,支持 在创建Bean的过程中能对Bean进行自动装配


ConfigurableBeanFactory

在HierarchicalBeanFactory和SingletonBeanRegistry的基础上, 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置 Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示 该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持 Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能


AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactor, 继承了AbstractBeanFactory,实现了 AutowireCapableBeanFactory,拥有了自动装配的功能


对于这些接口 , 类不明白也没关系, 着重理解BeanFactory就行 , 其实这也可以充分的体会到Spring内部这种面向接口的思想 , 在以后的工作中 ,我们也可以模仿Spring这种面向接口的设计思想 , 每一个接口都是一个功能 , 如果想拥有这个功能 , 那我们实现这个接口就行


ApplicationContext

上面有分析到,ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory 更加强大,比如:


HierarchicalBeanFactory

拥有获取父BeanFactory的功能


ListableBeanFactory

拥有获取beanNames的功能


ResourcePatternResolver

资源加载器,可以一次性获取多个资源(文件资源等等)


public class TestSpring {
  public static void main(String[] args) throws IOException {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  Resource resource = applicationContext.getResource("file://E:\\studywork\\spring-framework-5.3.10\\spring-lyh\\src\\main\\java\\com\\lyh\\service\\UserService.java");
  System.out.println(resource.contentLength());
  System.out.println(resource.getFilename());
  Resource resource1 = applicationContext.getResource("https://www.baidu.com");
  System.out.println(resource1.contentLength());
  System.out.println(resource1.getURL());
  Resource resource2 = applicationContext.getResource("classpath:spring.xml");
  System.out.println(resource2.contentLength());
  System.out.println(resource2.getURL());
  String message = applicationContext.getMessage("test", null, new Locale("en"));
  System.out.println("message : " + message);
  }
}

还可以一次性获取多个


Resource[] resources = applicationContext.getResources("classpath:com/lyh/*.class");
  for (Resource re : resources) {
    System.out.println(re.contentLength());
    System.out.println(re.getFilename());
  }


源码中是在扫描的时候用到的 , 这一块的源码之前有详细的入口 , 不清楚的可以在本篇文章中Ctrl+f搜一下这个方法 , 这个方法就会传入一个包路径 , 然后加载资源

e889636683a6ab6ab18aa92f17c381f4_4e02f474f4714c158bc9c45282a324e4.png

在开发中我们可以这样使用


@Component
public class MemberService implements ApplicationContextAware {
  private ApplicationContext applicationContext;
  @Override
  public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
  this.applicationContext = applicationContext;
  }
  public void test1(){
  Resource resource = applicationContext.getResource("");
  System.out.println("test1方法被调用 resource " + resource);
  }
}

EnvironmentCapable

可以获取运行时环境(没有设置运行时环境功能)


public class TestSpring {
  public static void main(String[] args){
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  // 获取操作系统层面的环境变量
  Map systemEnvironment = applicationContext.getEnvironment().getSystemEnvironment();
  System.out.println(systemEnvironment);
  System.out.println("=======");
  // 获取通过-d的方式指定的配置文件
  Map systemProperties = applicationContext.getEnvironment().getSystemProperties();
  System.out.println(systemProperties);
  System.out.println("=======");
  // 获取通过注解指定的配置文件的值 : @PropertySource("classpath:spring.properties")
  MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
  System.out.println(propertySources);
  System.out.println("=======");
  // 也可以指定具体的值 操作系统
  System.out.println(applicationContext.getEnvironment().getProperty("NO_PROXY"));
  // 通过-d指定的参数
  System.out.println(applicationContext.getEnvironment().getProperty("sun.jnu.encoding"));
  // 获取spring.properties配置文件的内容
  System.out.println(applicationContext.getEnvironment().getProperty("lyh"));
  }
}


ApplicationEventPublisher

拥有广播事件的功能(没有添加事件监听器的功能)

首先在Appconfig定义一个事件发布器


@Bean
  public ApplicationListener applicationListener() {
  return new ApplicationListener() {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    System.out.println("接收到了一个事件 : " + event);
    }
  };
  }

在工作中我们也可以这样用


@Component
public class MemberService implements ApplicationContextAware {
  private ApplicationContext applicationContext;
  @Override
  public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
  this.applicationContext = applicationContext;
  }
  public void test(){
  String message = applicationContext.getMessage("test", null, new Locale("en"));
  System.out.println("test方法被调用 message为 " + message);
  }
  public void test1(){
  Resource resource = applicationContext.getResource("");
  System.out.println("test1方法被调用 resource " + resource);
  }
  public void test2(){
  applicationContext.publishEvent("kkk");
  System.out.println("test2方法被调用 发布了事件");
  }
}

当我们调用test2()方法时就会发布一个事件


MessageSource

拥有国际化功能

我们首先在resources下新建一个文件

右键resources --> new --> resource Bundle , 然后就会出来如下图所示的界面 , 我们首先定义一个名称 : message(名称随意) , 然后添加一个英语 , 点击确认

eab4a3c0acd5282220a284b7e0c97eb6_1549586c36ea4ba0858acb8d94d0e9b5.png

然后就会帮我们创建出两个文件

a9a818069a5b2b93345e4d5bb5860eac_fb21856f9a204d36ab0c5cd48a3ca4a8.png

我们在两个文件中指定如下内容 , 内容随意

f84561cddd93d3a5470fb211783ab057_2417591a0cf5498fa39882ae9dd47d56.png

在AppConfig中定义一个MessageSource


@Bean
  public MessageSource messageSource() {
  ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
  messageSource.setBasename("message");
  return messageSource;
  }

有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。

同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:


public class TestSpring {
  public static void main(String[] args) {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  // en对应配置文件message_en的'en'
  String message = applicationContext.getMessage("test", null, new Locale("en"));
  System.out.println(message);
  }
}


但是我们在实际开发中肯定不是以这样的方式去获取国际化资源 , 那么应该怎么做呢?


@Component
public class MemberService implements ApplicationContextAware {
  private ApplicationContext applicationContext;
  @Override
  public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
  this.applicationContext = applicationContext;
  }
  public void test(){
  String message = applicationContext.getMessage("test", null, new Locale("en"));
  System.out.println("test方法被调用 message为 " + message);
  }


就像这样 , 我们实现一下ApplicationContextAware接口 , 这样不就想怎么用就怎么用了吗


关于ApplicationContext我们也有两个经常使用的具体的实现类


AnnotationConfigApplicationContext

49bc59d598d7e2dae552d9057d1f24f6_6d84ab4da75f4c4c98bdc6475432e2f4.png


ConfigurableApplicationContext

继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能


AbstractApplicationContext

实现了ConfigurableApplicationContext接口 , AbstractApplicationContext是Spring应用上下文中最重要的一个类,这个抽象类中提供了几乎ApplicationContext的所有操作。主要有容器工厂的处理,事件的发送广播,监听器添加,容器初始化操作refresh方法,然后就是bean的生成获取方法接口等。主要还是提供了一些方法,复杂的操作也是没有太多。


GenericApplicationContext

继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)


AnnotationConfigRegistry

可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描


AnnotationConfigApplicationContext

继承了GenericApplicationContext,实现了AnnotationConfigRegistry


AnnotationConfigRegistry

拥有了以上所有的功能


ClassPathXmlApplicationContext


它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition , 并且现在用AnnotationConfigApplicationContext比较多一点 , 所以ClassPathXmlApplicationContext就不着重说了


PropertyEditor

这其实是JDK中提供的类型转化工具类 , 在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。


定义类型转换器

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
 @Override
 public void setAsText(String text) throws IllegalArgumentException {
  User user = new User();
  user.setName(text);
  this.setValue(user);
 }
}


StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
// 设置要转换的值
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);

如何向Spring中注册PropertyEditor:


@Bean
  public CustomEditorConfigurer customEditorConfigurer() {
  CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
  Map, Class> propertyEditorMap = new HashMap<>();
  // 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
  propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
  customEditorConfigurer.setCustomEditors(propertyEditorMap);
  return customEditorConfigurer;
  }


假设现在有如下Bean:


@Component
  public class UserService {
  @Value("lyh")
  private User user;
  public void test() {
    System.out.println(user);
  }
  }


当我们使用/@Value(“lyh”)想为user赋值时 , Spring就会去看程序员有没有定义一个类型转换器 , 可以把String转换为user, 因为我们刚刚向容器注册了一个类型转换器, 那么user属性就能正常的完成属性赋值


ConversionService
Spring中提供的类型转化服务,它比PropertyEditor更强大
public class StringToUserConverter implements ConditionalGenericConverter {
  @Override
  public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
  // sourceType.getType() : 带转换的类型
  // targetType.getType(): 转换后类型
  return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
  }
  @Override
  public Set getConvertibleTypes() {
  return Collections.singleton(new ConvertiblePair(String.class, User.class));
  }
  @Override
  public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
  // 转换的逻辑
  User user = new User();
  user.setName((String)source);
  return user;
  }
}
public class TestSpring {
  public static void main(String[] args){
  DefaultConversionService conversionService = new DefaultConversionService();
  conversionService.addConverter(new StringToUserConverter());
  User value = conversionService.convert("1", User.class);
  System.out.println(value);
  }
}

如何向Spring中注册ConversionService:


@Bean
  public ConversionServiceFactoryBean conversionService() {
  ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
  conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
  return conversionServiceFactoryBean;
  }


TypeConverter

整合了PropertyEditor和ConversionService的功能,是Spring内部用的 , 因为我们在实际使用的时候可能会同时定义PropertyEditor和ConversionService , 所以Spring就用SimpleTypeConverter来把两种方式都添加进去


public class TestSpring {
  public static void main(String[] args){
  SimpleTypeConverter typeConverter = new SimpleTypeConverter();
  typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
  //typeConverter.setConversionService(conversionService);
  User value = typeConverter.convertIfNecessary("1", User.class);
  System.out.println(value);
  }


这个类型转换器在源码中是这样体现的


AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  MemberService memberService =  applicationContext.getBean("memberService" , MemberService.class);
  System.out.println(memberService);


这样我们就不用强制转换了 , 我们来看看源码 , 我们进入到doGetBean()方法


@Override
  public  T getBean(String name, Class requiredType) throws BeansException {
  assertBeanFactoryActive();
  return getBeanFactory().getBean(name, requiredType);
  }


继续进入getBean() , 此时应该到了BeanFactory的getBean();


T getBean(String name, Class requiredType) throws BeansException;

然后进入到AbstractBeanFactory的getBean();


@Override
  public  T getBean(String name, Class requiredType) throws BeansException {
  return doGetBean(name, requiredType, null, false);
  }

进入到doGetBean()即可


最后会看到

return adaptBeanInstance(name, beanInstance, requiredType);

7f1ea3ea8282d2d7376979c89d0e6682_26fb5c1eed914123a6e0314f41c1280b.png

它首先判断当前Bean的类型是否和给定的类型相符 , 如果不同 , 就会进行类型转换 , 能不能转的过来 , 就要看有没有定义上面的这些类型转换器 , 如果可以强转, 那么就返回 , 如果不可以强转, 那么就会报异常, 类型不符 , 如果没有指定 , 就直接返回


OrderComparator

OrderComparator是Spring所提供的一种比较器,可以用来根据@Order注解或实现Ordered接口来执行值进行笔记,从而可以进行排序 , 比如:


public class A implements Ordered {
  @Override
  public int getOrder() {
  return 3;
  }
  @Override
  public String toString() {
  return this.getClass().getSimpleName();
  }
}


public class B implements Ordered {
  @Override
  public int getOrder() {
  return 2;
  }
  @Override
  public String toString() {
  return this.getClass().getSimpleName();
  }
}


public class Main {
  public static void main(String[] args) {
  A a = new A(); // order=3
  B b = new B(); // order=2
  OrderComparator comparator = new OrderComparator();
  System.out.println(comparator.compare(a, b));  // 1
  List list = new ArrayList<>();
  list.add(a);
  list.add(b);
  // 按order值升序排序
  list.sort(comparator);
  System.out.println(list);  // B,A
  }
}


另外,Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。比如:


@Order(3)
public class A {
  @Override
  public String toString() {
  return this.getClass().getSimpleName();
  }
}


@Order(2)
public class B {
  @Override
  public String toString() {
  return this.getClass().getSimpleName();
  }
}
public class Main {
  public static void main(String[] args) {
  A a = new A(); // order=3
  B b = new B(); // order=2
  AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
  System.out.println(comparator.compare(a, b)); // 1
  List list = new ArrayList<>();
  list.add(a);
  list.add(b);
  // 按order值升序排序
  list.sort(comparator);
  System.out.println(list); // B,A
  }
}


BeanPostProcessor

BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,比如通过一下代码定义一个BeanPostProcessor:


@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  if ("userService".equals(beanName)) {
   System.out.println("初始化前");
  }
  return bean;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  if ("userService".equals(beanName)) {
   System.out.println("初始化后");
  }
  return bean;
 }
}

一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。


我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。


BeanFactoryPostProcessor

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。比如,我们可以这样定义一个BeanFactoryPostProcessor:


@Component
public class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
 @Override
 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  System.out.println("加工beanFactory");
 }
}


我们可以在postProcessBeanFactory()方法中对BeanFactory进行加工。


FactoryBean

上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean:

@Component
public class LyhFactoryBean implements FactoryBean {
 @Override
 public Object getObject() throws Exception {
  UserService userService = new UserService();
  return userService;
 }
 @Override
 public Class getObjectType() {
  return UserService.class;
 }
}


通过上面这段代码,我们自己创造了一个UserService对象,并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。


有同学可能会想到,通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?


其实在很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。而FactoryBean只是经过了初始化后这一步 , 因为虽然是以实现FactoryBean重写方法的方式定义的Bean , 但是不能把AOP这个功能给抛弃了


它的源码也是在doGetBean() , 如下图 , 一定要注意transformedBeanName()这个方法 , 等等我们来讲用途

fdded5f491922f374a22f89cd0ed9e61_aeef09f5a472409f92c3ec053cba29f3.png

它会判断 , 如果没有实现FactoryBean ,会直接返回 , 否则进行处理

97884f4a58e7bb0686cc24d92df2a498_7de5cd599d58411e86c5ed72c1711cec.png

e43f85201f644304b581cb1225c654a6_7a3f4f7e3185445796026bd869cdfc3d.png


77b335e54d6ded0a3d5f85469b485b78_3519f0994f9f4f02b014d99a93e74f85.png

到这里 , 它就会执行getObject()方法 , 然后返回 , getObject()方法也就是你自己实现了FactoryBean接口所重写的方法


然后我们再来说第一张图片的transformedBeanName()方法 , 如果实现了FactoryBean , 那么这个类也是一个Bean ,那么我们想获取这个Bean怎么获取呢?就比如上面的例子 , 我想获取LyhFactoryBean , 怎么获取呢?


public class TestSpring {
  public static void main(String[] args){
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  // 返回getObject()方法返回的Bean
  UserService userService = (UserService)applicationContext.getBean("lyhFactoryBean");
  System.out.println(userService);
  // 返回LyhFactoryBean
  LyhFactoryBean lyhFactoryBean = (LyhFactoryBean)applicationContext.getBean("&lyhFactoryBean");
  System.out.println(lyhFactoryBean);


所以transformedBeanName()方法其实是针对这种情况做了处理


ExcludeFilter和IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器。


比如以下配置,表示扫描com.lyh这个包下面的所有类,但是排除UserService类,也就是就算它上面有

@Component注解也不会成为Bean。


@ComponentScan(value = "com.lyh",
  excludeFilters = {@ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE, 
             classes = UserService.class)}.)
public class AppConfig {
}


再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。

@ComponentScan(value = "com.lyh",
  includeFilters = {@ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE, 
             classes = UserService.class)})
public class AppConfig {
}


FilterType分为:


ANNOTATION:表示是否包含某个注解

ASSIGNABLE_TYPE:表示是否是某个类

ASPECTJ:表示否是符合某个Aspectj表达式

REGEX:表示是否符合某个正则表达式

CUSTOM:自定义



在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下Spring扫描过程中会认为类上有@Component注解的就是Bean。


MetadataReader、ClassMetadata、AnnotationMetadata

在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。


MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:

public class Test {
 public static void main(String[] args) throws IOException {
  SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.zhouyu.service.UserService");
        // 得到一个ClassMetadata,并获取了类名
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println(classMetadata.getClassName());
        // 获取一个AnnotationMetadata,并获取类上的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
  for (String annotationType : annotationMetadata.getAnnotationTypes()) {
   System.out.println(annotationType);
  }
 }
}


那么有人会想 , 为什么不用反射呢?

其实SimpleMetadataReaderFactory类的功能是非常强大的 , 它可以获取接口的名称 , 获取内部类的名称 , 通过一个方法的直接调用就可以 , 但是用反射获取要写不少代码 , 对于这些类的API大家可以动手来试验一下 , 更容易理解


需要注意的是SimpleMetadataReader去解析类时,使用的ASM技术。

为什么要使用ASM技术


Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。


本篇文章到这里就结束了 , 介绍了Spring一些比较重要的常用的类的基本功能 , 概念, 在阅读Spring的源码中 , 我们可以知道个所以然 , 知道大概是干什么用的 , 这样会比较方便一点

相关文章
|
16天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
45 2
|
21天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
79 6
|
21天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
32 1
|
16天前
|
存储 分布式计算 关系型数据库
架构/技术框架调研
本文介绍了微服务间事务处理、调用、大数据处理、分库分表、大文本存储及数据缓存的最优解决方案。重点讨论了Seata、Dubbo、Hadoop生态系统、MyCat、ShardingSphere、对象存储服务和Redis等技术,提供了详细的原理、应用场景和优缺点分析。
|
22天前
|
监控
SMoA: 基于稀疏混合架构的大语言模型协同优化框架
通过引入稀疏化和角色多样性,SMoA为大语言模型多代理系统的发展开辟了新的方向。
32 6
SMoA: 基于稀疏混合架构的大语言模型协同优化框架
|
22天前
|
Kubernetes Cloud Native 云计算
云原生技术深度解析:重塑企业IT架构的未来####
本文深入探讨了云原生技术的核心理念、关键技术组件及其对企业IT架构转型的深远影响。通过剖析Kubernetes、微服务、容器化等核心技术,本文揭示了云原生如何提升应用的灵活性、可扩展性和可维护性,助力企业在数字化转型中保持领先地位。 ####
|
23天前
|
运维 Kubernetes Cloud Native
Kubernetes云原生架构深度解析与实践指南####
本文深入探讨了Kubernetes作为领先的云原生应用编排平台,其设计理念、核心组件及高级特性。通过剖析Kubernetes的工作原理,结合具体案例分析,为读者呈现如何在实际项目中高效部署、管理和扩展容器化应用的策略与技巧。文章还涵盖了服务发现、负载均衡、配置管理、自动化伸缩等关键议题,旨在帮助开发者和运维人员掌握利用Kubernetes构建健壮、可伸缩的云原生生态系统的能力。 ####
|
26天前
|
机器学习/深度学习 人工智能 自然语言处理
医疗行业的语音识别技术解析:AI多模态能力平台的应用与架构
AI多模态能力平台通过语音识别技术,实现实时转录医患对话,自动生成结构化数据,提高医疗效率。平台具备强大的环境降噪、语音分离及自然语言处理能力,支持与医院系统无缝集成,广泛应用于门诊记录、多学科会诊和急诊场景,显著提升工作效率和数据准确性。
|
15天前
|
API 持续交付 网络架构
深入解析微服务架构:原理、优势与实践
深入解析微服务架构:原理、优势与实践
17 0
|
24天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
23 0

推荐镜像

更多