• Spring-底层架构核心概念


    Spring底层核心组件

    BeanDefinition

    BeanDefinition表示Bean定义,有很多属性用来描述Bean的特点:

    • class,表示Bean类型

    • scope,表示Bean作用域,单例或原型等

    • lazyInit:表示Bean是否是懒加载

    • initMethodName:表示Bean初始化时要执行的方法

    • destroyMethodName:表示Bean销毁时要执行的方法

    • 还有很多...

    定义Bean的方式主要分为两种:

    • 申明式定义

      1. 1
      2. 2@Bean
      3. 3@Component(@Service,@Controller)
    • 编程式定义

      1. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
      2. // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
      3. AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
      4. beanDefinition.setBeanClass(User.class);
      5. beanDefinition.setScope("prototype"); // 设置作用域
      6. beanDefinition.setInitMethodName("init"); // 设置初始化方法
      7. beanDefinition.setLazyInit(true); // 设置懒加载
      8. context.registerBeanDefinition("user", beanDefinition);
      9. System.out.println(context.getBean("user"));

    BeanDefinitionReader

    BeanDefinition读取器,虽然开发中用的很少,但是源码中用得很多

    AnnotatedBeanDefinitionReader

    把某个类转换为BeanDefinition,并且解析类上的注解

    1. AnnotationConfigApplicationContext context = new
    2. AnnotationConfigApplicationContext(AppConfig.class);
    3. AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
    4. // 将User.class解析为BeanDefinition
    5. annotatedBeanDefinitionReader.register(User.class);
    6. System.out.println(context.getBean("user"));

    可以解析的注解:@Conditional、@Scope、@Lazy、@Primary、@DependsOn、 @Role、@Description

    XmlBeanDefinitionReader

    解析标签

    1. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    2. XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
    3. int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
    4. System.out.println(context.getBean("user"));

    ClassPathBeanDefinitionScanner

    扫描器,可以进行扫描,扫描某个包路径,对扫描到的类进行解析

    1. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    2. context.refresh();
    3. ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
    4. scanner.scan("com.gax");
    5. System.out.println(context.getBean("userService"));

    BeanFactory

    Bean工厂,负责创建Bean,并且提供获取Bean的 API

    ApplicationContext就是BeanFactory的一种

    1. public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
    2. HierarchicalBeanFactory,
    3. MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    4. ...
    5. }
    6. HierarchicalBeanFactory: 支持父子Bean工厂,子Bean工厂获取不到时,可以到父Bean工厂去获取
    7. ListableBeanFactory: 展示Bean的名字、展示Bean的数量、统计的信息、拿某一个类型的Bean,类似列表的功能
    8. EnvironmentCapable: 获取环境变量的功能
    9. ApplicationEventPublisher: 事件发布的功能
    10. MessageSource: 国际化的功能
    11. ResourcePatternResolver: 获取某些资源、解析某些资源的功能

    Spring源码中,BeanFactory接口非常重要的实现类: DefaultListableBeanFactory

    ApplicationContext.getBean() 调用的就是 DefaultListableBeanFactory 的getBean()方法

    DefaultListableBeanFactory 可以单独使用:

    1. DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    2. AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    3. beanDefinition.setBeanClass(User.class);
    4. beanFactory.registerBeanDefinition("user", beanDefinition);
    5. System.out.println(beanFactory.getBean("user"));

    ApplicationContext

    ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory 更加强大:

    1、HierarchicalBeanFactory:拥有获取父BeanFactory的功能

    2、ListableBeanFactory:拥有获取beanNames的功能

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

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

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

    6、MessageSource:拥有国际化功能

    ApplicationContext两个重要的实现类:

    1、AnnotationConfigApplicationContext

    2、ClassPathXmlApplicationContext

    国际化

    定义一个MessageSource

    1. @Bean
    2. public MessageSource messageSource() {
    3. ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    4. messageSource.setBasename("messages");
    5. return messageSource;
    6. }

    ApplicationContext拥有国际化的功能,可以直接用

    context.getMessage("test", null, new Locale("en_CN"))

    资源加载

    可以利用ApplicationContext获取某个文件的内容

    1. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    2. Resource resource = context.getResource("file://D:\\UserService.java");
    3. System.out.println(resource.contentLength());
    4. System.out.println(resource.getFilename());
    5. Resource resource1 = context.getResource("https://www.baidu.com");
    6. System.out.println(resource1.contentLength());
    7. System.out.println(resource1.getURL());
    8. Resource resource2 = context.getResource("classpath:spring.xml");
    9. System.out.println(resource2.contentLength());
    10. System.out.println(resource2.getURL());
    11. Resource[] resources = context.getResources("classpath:com/gax/*.class");
    12. for (Resource resource : resources) {
    13. System.out.println(resource.contentLength());
    14. System.out.println(resource.getFilename());
    15. }

    获取运行时环境

    1. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    2. Map systemEnvironment = context.getEnvironment().getSystemEnvironment();
    3. System.out.println(systemEnvironment); //操作系统层面的环境变量
    4. Map systemProperties = context.getEnvironment().getSystemProperties();
    5. System.out.println(systemProperties); //运行java通过-D指定的环境变量
    6. MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
    7. System.out.println(propertySources); //最强大的,包含上面两种和PropertySources注解的变量
    8. System.out.println(context.getEnvironment().getProperty("NO_PROXY")); //操作系统
    9. System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding")); //jvm -D指定
    10. System.out.println(context.getEnvironment().getProperty("gax")); //property里面的

    事件发布

    定义一个事件监听器

    1. @Bean
    2. public ApplicationListener applicationListener() {
    3. return new ApplicationListener() {
    4. @Override
    5. public void onApplicationEvent(ApplicationEvent event) {
    6. System.out.println("接收到了一个事件");
    7. }
    8. };
    9. }

    发布一个事件

    context.publishEvent("yeah");

    类型转化

    Spring提供了一些方便类型转化的技术

    PropertyEditor

    JDK中提供的类型转化工具类,使用示例:

    1. public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor
    2. {
    3. @Override
    4. public void setAsText(String text) throws IllegalArgumentException
    5. {
    6. User user = new User();
    7. user.setName(text);
    8. this.setValue(user);
    9. }
    10. // 单独使用示例
    11. public static void main(String[] args)
    12. {
    13. StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
    14. propertyEditor.setAsText("11");
    15. User value = (User)propertyEditor.getValue();
    16. System.out.println(value);
    17. System.out.println(value.getName());
    18. }
    19. }
    20. 输出:
    21. com.gax.service.User@5a07e868
    22. 11

    向Spring中注册PropertyEditor:

    1. @Bean
    2. public CustomEditorConfigurer customEditorConfigurer()
    3. {
    4. CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
    5. Map, Class> propertyEditorMap = new HashMap<>();
    6. // StringToUserPropertyEditor可以将String转化成User类型,
    7. // 在Spring源码中,如果当前对象是String,而需要的类型是User,就会用该PropertyEditor做类型转化
    8. propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
    9. customEditorConfigurer.setCustomEditors(propertyEditorMap);
    10. return customEditorConfigurer;
    11. }
    12. // 示例代码
    13. @Component
    14. public class UserService
    15. {
    16. @Value("ccc")
    17. private User user; //这里需要类型转换
    18. public void test()
    19. {
    20. System.out.println(user);
    21. }
    22. }
    23. // 测试
    24. public class Test
    25. {
    26. public static void main(String[] args)
    27. {
    28. // 创建一个Spring容器
    29. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    30. UserService userService = (UserService) applicationContext.getBean("userService");
    31. userService.test();
    32. }
    33. }
    34. 输出:(输出的是一个User,转换成功)
    35. com.gax.service.User@17ed40e0

    ConversionService

    Spring中提供的类型转化服务,它比PropertyEditor更强大

    1. public class StringToUserConverter implements ConditionalGenericConverter
    2. {
    3. @Override
    4. public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType)
    5. {
    6. return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
    7. }
    8. @Override
    9. public Set getConvertibleTypes()
    10. {
    11. return Collections.singleton(new GenericConverter.ConvertiblePair(String.class, User.class));
    12. }
    13. @Override
    14. public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType)
    15. {
    16. User user = new User();
    17. user.setName((String)source);
    18. return user;
    19. }
    20. }
    21. // 单独使用
    22. public class Test
    23. {
    24. public static void main(String[] args)
    25. {
    26. DefaultConversionService conversionService = new DefaultConversionService();
    27. conversionService.addConverter(new StringToUserConverter());
    28. User value = conversionService.convert("1", User.class);
    29. System.out.println(value);
    30. }
    31. }

    向Spring中注册ConversionService:

    1. @Bean
    2. public ConversionServiceFactoryBean conversionService()
    3. {
    4. ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
    5. conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
    6. return conversionServiceFactoryBean;
    7. }

    TypeConverter

    Spring提供更高级的转换类SimpleTypeConverter,可以支持上面两种

    1. public class Test
    2. {
    3. public static void main(String[] args)
    4. {
    5. SimpleTypeConverter typeConverter = new SimpleTypeConverter();
    6. typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
    7. // DefaultConversionService conversionService = new DefaultConversionService();
    8. // conversionService.addConverter(new StringToUserConverter());
    9. // typeConverter.setConversionService(conversionService);
    10. User value = typeConverter.convertIfNecessary("1", User.class);
    11. System.out.println(value);
    12. }
    13. }

    扩展:

    1. // getBean指定类型转换
    2. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    3. UserService userService = applicationContext.getBean("userService", UserService.class);
    4. // 可以对应到Spring源码:AbstractBeanFactory#adaptBeanInstance
    5. T adaptBeanInstance(String name, Object bean, @Nullable Class requiredType) {
    6. // Check if required type matches the type of the actual bean instance.
    7. if (requiredType != null && !requiredType.isInstance(bean)) {
    8. try {
    9. // SimpleTypeConverter
    10. Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
    11. if (convertedBean == null) { // 已经转换过了返回,没转换报错
    12. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    13. }
    14. return (T) convertedBean;
    15. }
    16. catch (TypeMismatchException ex) {
    17. if (logger.isTraceEnabled()) {
    18. logger.trace("Failed to convert bean '" + name + "' to required type '" +
    19. ClassUtils.getQualifiedName(requiredType) + "'", ex);
    20. }
    21. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    22. }
    23. }
    24. return (T) bean;
    25. }

    OrderComparator

    Spring所提供的一种比较器,有@Order注解、实现Ordered接口两种使用方式,通过指定的值进行比较或排序。

    实现Ordered接口示例代码:

    1. public class A implements Ordered
    2. {
    3. @Override
    4. public int getOrder()
    5. {
    6. return 3;
    7. }
    8. @Override
    9. public String toString()
    10. {
    11. return this.getClass().getSimpleName();
    12. }
    13. }
    14. public class B implements Ordered
    15. {
    16. @Override
    17. public int getOrder()
    18. {
    19. return 2;
    20. }
    21. @Override
    22. public String toString()
    23. {
    24. return this.getClass().getSimpleName();
    25. }
    26. }
    27. public class Main
    28. {
    29. public static void main(String[] args)
    30. {
    31. A a = new A(); // order=3
    32. B b = new B(); // order=2
    33. OrderComparator comparator = new OrderComparator();
    34. System.out.println(comparator.compare(a, b)); // 1 (a>b,a
    35. List list = new ArrayList<>();
    36. list.add(a);
    37. list.add(b);
    38. // 按order值升序排序
    39. list.sort(comparator);
    40. System.out.println(list); // B,A
    41. }
    42. }
    43. 输出:
    44. 1
    45. [B, A]

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

    1. @Order(3)
    2. public class A
    3. {
    4. @Override
    5. public String toString()
    6. {
    7. return this.getClass().getSimpleName();
    8. }
    9. }
    10. @Order(2)
    11. public class B
    12. {
    13. @Override
    14. public String toString()
    15. {
    16. return this.getClass().getSimpleName();
    17. }
    18. }
    19. public class Main
    20. {
    21. public static void main(String[] args)
    22. {
    23. A a = new A(); // order=3
    24. B b = new B(); // order=2
    25. AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
    26. System.out.println(comparator.compare(a, b)); // 1
    27. List list = new ArrayList<>();
    28. list.add(a);
    29. list.add(b);
    30. // 按order值升序排序
    31. list.sort(comparator);
    32. System.out.println(list); // B,A
    33. }
    34. }
    35. 输出:
    36. 1
    37. [B, A]
    38. // 关键源码:AnnotationAwareOrderComparator#findOrder
    39. protected Integer findOrder(Object obj) {
    40. // 先获取Ordered接口中getOrder()方法返回的数值
    41. Integer order = super.findOrder(obj);
    42. if (order != null) {
    43. return order;
    44. }
    45. // 如果没有实现Ordered接口,则获取@Order注解中指定的值
    46. return findOrderFromAnnotation(obj);
    47. }

    BeanPostProcessor

    BeanPostProcess表示Bean的后置处理器,可以定义一个或多个BeanPostProcessor

    1. @Component
    2. public class GaxBeanPostProcessor implements BeanPostProcessor
    3. {
    4. @Override
    5. public Object postProcessBeforeInitialization(Object bean, String beanName)
    6. {
    7. if ("userService".equals(beanName))
    8. {
    9. System.out.println("初始化前");
    10. }
    11. return bean;
    12. }
    13. @Override
    14. public Object postProcessAfterInitialization(Object bean, String beanName)
    15. {
    16. if ("userService".equals(beanName))
    17. {
    18. System.out.println("初始化后");
    19. }
    20. return bean;
    21. }
    22. }

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

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

    BeanFactoryPostProcessor

    Bean工厂的后置处理器,和BeanPostProcessor类似。

    BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。

    1. @Component
    2. public class GaxBeanFactoryPostProcessor implements BeanFactoryPostProcessor
    3. {
    4. @Override
    5. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
    6. {
    7. System.out.println("加工beanFactory");
    8. }
    9. }

    FactoryBean

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

    1. @Component
    2. public class GaxFactoryBean implements FactoryBean
    3. {
    4. @Override
    5. public Object getObject()
    6. {
    7. return new UserService();
    8. }
    9. @Override
    10. public Class getObjectType()
    11. {
    12. return UserService.class;
    13. }
    14. }
    15. // 测试
    16. public class Test
    17. {
    18. public static void main(String[] args) throws IOException
    19. {
    20. // 创建一个Spring容器
    21. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    22. Object gaxFactoryBean = applicationContext.getBean("gaxFactoryBean");
    23. Object gaxFactoryBean2 = applicationContext.getBean("&gaxFactoryBean");
    24. Object gaxFactoryBean3 = applicationContext.getBean("&&&&&&gaxFactoryBean");
    25. System.out.println(gaxFactoryBean);
    26. System.out.println(gaxFactoryBean2);
    27. System.out.println(gaxFactoryBean3);
    28. }
    29. }
    30. 输出:
    31. com.gax.service.UserService@6e3c1e69
    32. com.gax.GaxFactoryBean@5f150435
    33. com.gax.GaxFactoryBean@5f150435

    注意:通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。

    通过@Bean也可以生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?

    其实在很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。

    ExcludeFilter和IncludeFilter

    ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器

    1. // 扫描com.gax这个包下面的所有类,但是排除UserService类
    2. // 也就是就算类上面有@Component注解也不会成为Bean
    3. @ComponentScan(value = "com.gax", excludeFilters = {
    4. @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)})
    5. public class AppConfig {
    6. }
    7. // 就算UserService类上没有@Component注解,也会被扫描成为一个Bean
    8. @ComponentScan(value = "com.gax", includeFilters = {
    9. @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)})
    10. public class AppConfig {
    11. }

    FilterType分为:

    1、ANNOTATION:是否包含某个注解

    2、ASSIGNABLE_TYPE:是否是某个类

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

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

    5、CUSTOM:自定义

    Spring内部怎么支持@Component注解扫描的?

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

    1. // ClassPathScanningCandidateComponentProvider#registerDefaultFilters
    2. protected void registerDefaultFilters() {
    3. // 注册@Component对应的AnnotationTypeFilter
    4. this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    5. ... ...
    6. }

    MetadataReader、ClassMetadata、 AnnotationMetadata

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

    1. public interface MetadataReader {
    2. /**
    3. * Return the resource reference for the class file.
    4. */
    5. Resource getResource();
    6. /**
    7. * Read basic class metadata for the underlying class.
    8. */
    9. ClassMetadata getClassMetadata();
    10. /**
    11. * Read full annotation metadata for the underlying class,
    12. * including metadata for annotated methods.
    13. */
    14. AnnotationMetadata getAnnotationMetadata();
    15. }
    16. // 类的元数据
    17. public interface ClassMetadata {
    18. /**
    19. * Return the name of the underlying class.
    20. */
    21. String getClassName();
    22. /**
    23. * Return whether the underlying class represents an interface.
    24. */
    25. boolean isInterface();
    26. /**
    27. * Return whether the underlying class represents an annotation.
    28. * @since 4.1
    29. */
    30. boolean isAnnotation();
    31. /**
    32. * Return whether the underlying class is marked as abstract.
    33. */
    34. boolean isAbstract();
    35. /**
    36. * Return whether the underlying class represents a concrete class,
    37. * i.e. neither an interface nor an abstract class.
    38. */
    39. default boolean isConcrete() {
    40. return !(isInterface() || isAbstract());
    41. }
    42. ... ...
    43. }
    44. // 注解元数据
    45. public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
    46. /**
    47. * Get the fully qualified class names of all annotation types that
    48. * are present on the underlying class.
    49. * @return the annotation type names
    50. */
    51. default Set getAnnotationTypes() {
    52. return getAnnotations().stream()
    53. .filter(MergedAnnotation::isDirectlyPresent)
    54. .map(annotation -> annotation.getType().getName())
    55. .collect(Collectors.toCollection(LinkedHashSet::new));
    56. }
    57. /**
    58. * Determine whether an annotation of the given type is present on
    59. * the underlying class.
    60. * @param annotationName the fully qualified class name of the annotation
    61. * type to look for
    62. * @return {@code true} if a matching annotation is present
    63. */
    64. default boolean hasAnnotation(String annotationName) {
    65. return getAnnotations().isDirectlyPresent(annotationName);
    66. }
    67. /**
    68. * 可以判断类下面有没有指定注解,比如说判断一个类下面有没有@Bean修饰的方法
    69. * Determine whether the underlying class has an annotation that is itself
    70. * annotated with the meta-annotation of the given type.
    71. * @param metaAnnotationName the fully qualified class name of the
    72. * meta-annotation type to look for
    73. * @return {@code true} if a matching meta-annotation is present
    74. */
    75. default boolean hasMetaAnnotation(String metaAnnotationName) {
    76. return getAnnotations().get(metaAnnotationName,
    77. MergedAnnotation::isMetaPresent).isPresent();
    78. }
    79. ... ...
    80. }

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

    1. public class Test
    2. {
    3. public static void main(String[] args) throws IOException
    4. {
    5. SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
    6. // 构造一个MetadataReader
    7. MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.gax.service.UserService");
    8. // 得到一个ClassMetadata,并获取了类名
    9. ClassMetadata classMetadata = metadataReader.getClassMetadata();
    10. System.out.println(classMetadata.getClassName());
    11. // 获取一个AnnotationMetadata,并获取类上的注解信息
    12. AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    13. for (String annotationType : annotationMetadata.getAnnotationTypes())
    14. {
    15. System.out.println(annotationType);
    16. }
    17. }
    18. }
    19. 输出:
    20. com.gax.service.UserService
    21. org.springframework.stereotype.Component

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

    ASM简述:把类当成普通文件,通过字节流读出来,如果符合字节码规范,就根据字节码的格式获取类的信息

    为什么要使用ASM技术?

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

  • 相关阅读:
    6个步骤轻松实现 postman 接口压力测试(建议收藏)
    Android启动摄像机拍照&存储&展示
    解决计算机视觉模型中的种族和性别偏见问题,Meta开源 FACET工具
    MySQL日志
    《深入浅出OCR》第四章:OCR文字识别
    c++内存对齐
    文化融合与社交网络:Facebook的角色
    17、生成器
    利用共享台球室小程序系统提升用户体验
    IDEA本地将镜像推送到coding制品仓库
  • 原文地址:https://blog.csdn.net/weixin_58482311/article/details/134085792