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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 上面说到解析为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的源码中 , 我们可以知道个所以然 , 知道大概是干什么用的 , 这样会比较方便一点

相关文章
|
10天前
|
IDE Android开发 iOS开发
深入解析Android与iOS的系统架构及开发环境差异
本文旨在探讨Android和iOS两大主流移动操作系统在系统架构、开发环境和用户体验方面的显著差异。通过对比分析,我们将揭示这两种系统在设计理念、技术实现以及市场策略上的不同路径,帮助开发者更好地理解其特点,从而做出更合适的开发决策。
38 2
|
10天前
|
Java 对象存储 开发者
解析Spring Cloud与Netflix OSS:微服务架构中的左右手如何协同作战
Spring Cloud与Netflix OSS不仅是现代微服务架构中不可或缺的一部分,它们还通过不断的技术创新和社区贡献推动了整个行业的发展。无论是对于初创企业还是大型组织来说,掌握并合理运用这两套工具,都能极大地提升软件系统的灵活性、可扩展性以及整体性能。随着云计算和容器化技术的进一步普及,Spring Cloud与Netflix OSS将继续引领微服务技术的发展潮流。
24 0
|
7天前
|
物联网 5G SDN
5G 网络架构全解析:RAN、核心网和接入网
5G 网络架构全解析:RAN、核心网和接入网
39 8
|
11天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
554 6
|
7天前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
14 1
|
9天前
|
XML 前端开发 Java
控制spring框架注解介绍
控制spring框架注解介绍
|
9天前
|
存储 NoSQL Java
Spring Session框架
Spring Session 是一个用于在分布式环境中管理会话的框架,旨在解决传统基于 Servlet 容器的会话管理在集群和云环境中的局限性。它通过将用户会话数据存储在外部介质(如数据库或 Redis)中,实现了会话数据的跨服务器共享,提高了应用的可扩展性和性能。Spring Session 提供了无缝集成 Spring 框架的 API,支持会话过期策略、并发控制等功能,使开发者能够轻松实现高可用的会话管理。
Spring Session框架
|
10天前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
10天前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
2月前
|
Kubernetes Cloud Native Docker
云原生之旅:从容器到微服务的架构演变
【8月更文挑战第29天】在数字化时代的浪潮下,云原生技术以其灵活性、可扩展性和弹性管理成为企业数字化转型的关键。本文将通过浅显易懂的语言和生动的比喻,带领读者了解云原生的基本概念,探索容器化技术的奥秘,并深入微服务架构的世界。我们将一起见证代码如何转化为现实中的服务,实现快速迭代和高效部署。无论你是初学者还是有经验的开发者,这篇文章都会为你打开一扇通往云原生世界的大门。

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面