spring中的基本概念

 2023-01-12
原文作者:XL 原文地址:https://juejin.cn/post/7146134746651688990

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情

1.BeanDefinition

主要作用是用来封装bean的信息:类型,是否是懒加载,是否是单例等等。
在spring中BeanDefinition是一个接口,它会有各种各样的实现类,这里我们只需要知道,它就是用来封装bean基本信息的就行了。

202301012004122481.png

2.声明式定义bean 编程式定义bean,

声明式定义bean: @Bean @Component 或者是xml 中的bena标签
编程式定义bean: 就是使用代码来注册bean生命bean的一些信息:单例,懒加载,等等。
例如:

    public static void main(String[] args) {
          //ApplicationContext applicationContext = new ApplicationContext(UserService.class);
          //编程式
          AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserService.class);
          AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
          beanDefinition.setBeanClass(UserService.class);
          context.registerBeanDefinition("userService",beanDefinition);
          //
          UserService userService =  (UserService)context.getBean("userService");
          userService.test();
       }
    }

3. 读取器:AnnotatedBeanDefinitionReader

这个类是beanDefinition 读取器,可以将类封装成一个beanDefinition ,然后放入到spring容器当中变成一个bena。

    public class User {
    
      public void test(){
         System.out.println("123123123");
      }
    }
    public class Test {
    
      public static void main(String[] args) {
         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
         AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
         //注册一个bean
         reader.register(User.class);
         User user = (User)context.getBean("user");
         user.test();
      }
    }

我们看上面的代码,user类是没有加注解的,正常情况下是不可能加载到spring容器当中的。使用AnnotatedBeanDefinitionReader 的 register()方法就可以将User类变成beanDefinition然后放到spring容器当中。 我们看下这里面的源码:

    reader.register(User.class);
    /**
     * Register one or more component classes to be processed.
     * <p>Calls to {@code register} are idempotent; adding the same
     * component class more than once has no additional effect.
     * @param componentClasses one or more component classes,
     * e.g. {@link Configuration @Configuration} classes
     */
    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) {
        //创建一个beanDefinition 
       AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
       if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
          return;
       }
    
       abd.setInstanceSupplier(supplier);
       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);
    }

我们可以看到这个注册方法中创建了一个beanDefinition:

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

然后就是对这个beanDefinition 进行各种处理,以上就是这个类的主要作用。
我们看 AnnotationConfigApplicationContext 中的构造方法:

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
       this();
       register(componentClasses);
       refresh();
    }
    public AnnotationConfigApplicationContext() {
       StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
       this.reader = new AnnotatedBeanDefinitionReader(this);
       createAnnotatedBeanDefReader.end();
       this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

可以看到AnnotationConfigApplicationContext()方法中创建了一个 AnnotatedBeanDefinitionReader。并且register(componentClasses)方法中使用的就是这里创建的AnnotatedBeanDefinitionReader的注册方法。

4. 扫描器:ClassPathBeanDefinitionScanner

一般在创建spring容器的时候,会传一个配置类,配置类上会配置有扫描路径,spring就会知道要扫描哪个包下面的类。
那么在创建spring容器的时候不传配置类,可以通过 ClassPathBeanDefinitionScanner 的scan 方法传一个包路径,与传配置类的效果是一样的。

    public class Test {
    
       public static void main(String[] args) {
          AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
          context.refresh();
          ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
          scanner.scan("com.xl.service");
          User user = (User)context.getBean("user");
          user.test();
       }
    }

5.GenericBeanDefinition 及其子类

ClassPathBeanDefinitionScanner和AnnotatedBeanDefinitionReader都会生成beanDefinition但是他们生成的类型是不一样的。
AnnotatedBeanDefinitionReader 对应的:AnnotatedGenericBeanDefinition
ClassPathBeanDefinitionScanner 对应的:ScannedGenericBeanDefinition
这两个beanDefinition都继承了GenericBeanDefinition。

6.ApplicationContext 和 BeanFactory

202301012004129422.png

202301012004137333.png

对比下可以看到,ApplicationContext 继承了除beanFactory外的很多接口,beanFactory 只是一个单纯的接口。

  1. ApplicationContext 拥有BeanFactory的功能:创建bean 获取bean
  2. ApplicationContext 拥有事件发布(ApplicationEventPublisher),国际化(MessageSource),获取环境变量(EnvironmentCapable),获取某些资源(ResourcePatternResolver)的功能,
  3. BeanFactory 只拥有创建bena,获取bean的功能。

如果只是创建bean 和获取bean,那么使用beanFactory就可以了。

    public class Test {
    
       public static void main(String[] args) {
          DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
          AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
          beanDefinition.setBeanClass(User.class);
          beanFactory.registerBeanDefinition("user",beanDefinition);
          User user = (User)beanFactory.getBean("user");
          user.test();
       }
    }

DefaultListableBeanFactory 是beanFactory的一个实现类。AnnotationConfigApplicationContext中使用的就这个实现类。

    public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}
    public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    
       private final DefaultListableBeanFactory beanFactory;
    
       @Nullable
       private ResourceLoader resourceLoader;
    
       private boolean customClassLoader = false;
    
       private final AtomicBoolean refreshed = new AtomicBoolean();
    
    
       /**
        * Create a new GenericApplicationContext.
        * @see #registerBeanDefinition
        * @see #refresh
        */
       public GenericApplicationContext() {
          this.beanFactory = new DefaultListableBeanFactory();
       }
       }

以上源码只是一部分,可以看到AnnotationConfigApplicationContext继承了GenericApplicationContext,GenericApplicationContext中的beanFactory类型是DefaultListableBeanFactory。

202301012004142844.png

从上面这个类图可以看到,DefaultListableBeanFactory实现了很多接口,这些接口每个都有不同的功能,下面列举了一部分。
AliasRegistry:可以给bean起别名。
SingletonBeanRegistry:单例bean注册的功能。
BeanDefinitionRegistry:注册beanDefinition的功能。
HierarchicalBeanFactory:获取父beanFactory的功能。
ListableBeanFactory:判断是否包含这个beanDefinition,获取beanDefinition的名字 等功能
AutowireCapableBeanFactory:自动注入的beanFactory

7.MetadataReader ClassMetadata AnnotationMetadata

ClassMetadata :类的元数据信息。可以通过它来获取类的很多信息:父类的名字,接口的名字等等。
AnnotationMetadata: 注解的元数据信息。主要是获取一个类上面注解的相关信息.
它们与beanDefinition是不一样的,beanDefinition 是获取不到父类的名字,接口的名字的。所以,ClassMetadata 和 AnnotationMetadata 相比较beanDefinition 可以获取类的信息要全的多。

    public class Test {
    
       public static void main(String[] args) throws IOException {
          SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
          //创建一个metadataReader
          MetadataReader metadataReader = metadataReaderFactory.getMetadataReader("com.xl.service.User");
          //获取一个classMetadata
          ClassMetadata classMetadata = metadataReader.getClassMetadata();
          //获取类名
          System.out.println(classMetadata.getClassName());
          //获取内部类名
          System.out.println(classMetadata.getMemberClassNames()[0]);
          //获取一个annotationMetadata
          AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
          //获取类上注解的信息
          for (String type:annotationMetadata.getAnnotationTypes()){
             System.out.println(type);
          }
       }
    }

8.includeFilters 和 excludeFilters

excludeFilters排除,typ 属性可以指定类,注解等。 classes属性要指定排除的具体类或者注解。指定之后,spring是不对排除的注解或者类做任何处理的。

includeFilters包含,如果一个类没有加注解那么它是不会成为bean(一般情况下),但是它被includeFilters指定包含了,也会被sprig加载容器中成为bean。 以下这个这个两个的基本用法。

    @ComponentScan(value = "com.xl.service",
          includeFilters = {@ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE,
             classes = User.class
          )})
    public class AppConfig {
    }
    @ComponentScan(value = "com.xl.service",
          excludeFilters = {@ComponentScan.Filter(
             type = FilterType.ASSIGNABLE_TYPE,
             classes = User.class
          )})
    public class AppConfig {
    }
    public class User {
       public void test(){
          System.out.println("123123123");
       }
    }
    public class Test {
    
       public static void main(String[] args)  {
          AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
          User user = (User)context.getBean("user");
          user.test();
       }
    }

在spring中使用includeFilters, ClassPathScanningCandidateComponentProvider 类下registerDefaultFilters()方法中。 spring默认会添加一个includeFilters,只要在扫描的时候发现一个类上面带有@Component,它就会认为符合includeFilters,这个类就是一个bean,它就会解析这个类生成一个beanDefinition.

    protected void registerDefaultFilters() {
       this.includeFilters.add(new AnnotationTypeFilter(Component.class));
       ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
       try {
          this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
          logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
       }
       catch (ClassNotFoundException ex) {
          // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
       }
       try {
          this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
          logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
       }
       catch (ClassNotFoundException ex) {
          // JSR-330 API not available - simply skip.
       }
    }

9.FactoryBean

一个类实现了这个接口,那么在getBean的时候返回的是getObject()方法返回的bean。如果想获取原来的bean,getBean("&lynnFactoryBean")在名字前面加& 就可以。 并且这个返回的这个bean只经历初始化后这么一个过程,并没有经历完成的bean的生命周期。 以下是测试代码

    @Component("user")
    public class LynnFactoryBean implements FactoryBean<User> {
       @Override
       public User getObject() throws Exception {
          return new User();
       }
    
       @Override
       public Class<?> getObjectType() {
          return User.class;
       }
    }
    @Component
    public class LynnPostProcessor implements BeanPostProcessor {
    
       @Override
       public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
          if(beanName.equals("user")){
             System.out.println("qian  "+bean);
          }
    
          return bean;
       }
    
       @Override
       public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          if(beanName.equals("user")){
             System.out.println("hou:  "+bean);
          }
          return bean;
       }
    }
    @ComponentScan(value = "com.xl.service")
    public class AppConfig {
    }
    @Aspect
    @Component
    public class LynnAspect {
       @Before("execution(public void com.xl.service.User.test())")
       public void  before(JoinPoint joinPoint){
    
       }
    }
    public class Test {
    
      public static void main(String[] args)  {
         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         //这个返回的是User类型的bean
         System.out.println(context.getBean("user"));
         //这个返回的是 LynnFactoryBean类型的bean
         //System.out.println(context.getBean("&lynnFactoryBean"));
    
      }
    }

以上大致就是spring框架中一些基本概念,如有笔误还请指正。