BeanDefinition

BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。
比如:

  • class: 表示bean类型 ```java 为什么这里是Object,而不是Class<?>呢? 因为这里还没有加载,只是通过ASM技术去解析了这个类,并没有去解析, 只是把这个类的名字设置给了BeanDefinition的属性,当创建这个Bean的时候, 才会去真正的加载,所以这里使用的是Object

private volatile Object beanClass;

  1. - scope: 表示bean作用域,有singleprototyperequestsessionglobal
  2. - lazyInit: 表示Bean是否是懒加载的
  3. - initMethodName: 表示Bean初始化时要执行的方法
  4. - destoryMethodName: 表示Bean销毁时要执行的方法
  5. - 等等
  6. Spring中,我们经常会通过声明式定义Bean:
  7. - bean标签
  8. - @Bean
  9. - @Component@Service@Controller
  10. 我们也可以使用编程式定义Bean,那就是直接通过BeanDefinition
  11. ```java
  12. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  13. // 生成一个beanDefinition
  14. AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
  15. // 设置beanClass
  16. beanDefinition.setBeanClass(User.class);
  17. // 设置作用域
  18. beanDefinition.setScope("prototype");
  19. // 设置初始化方法
  20. beanDefinition.setInitMethodName("init");
  21. // 设置是否懒加载
  22. beanDefinition.setLazyInit(true);
  23. // 注册beanDefinition
  24. context.registerBeanDefinition("user", beanDefinition);
  25. System.out.println(context.getBean("user"));

这个和声明式事务、编程式事务类似,通过bean标签、@Bean等声明式所定义的Bean,最终都会被Spring解析为对应的BeanDefinition对象,并且放入Spring容器中。

BeanDefinitionReader

AnnotatedBeanDefinitionReader

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

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析成BeanDefinition
reader.register(User.class);
System.out.println(context.getBean("user"));

==注意==: 它能解析的注解是: @Conditional、@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

XmlBeanDefinitionReader

可以解析Bean标签

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
int i = reader.loadBeanDefinitions("spring.xml");
System.out.println(i);
System.out.println(context.getBean("user"));

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("linc.cool");
System.out.println(context.getBean("userService"));

BeanFactory

BeanFactory表示Bean工厂,BeanFactory会负责创建Bean,并且提供获取Bean的API. 而ApplicationContext是BeanFactory的一种

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

        }

ApplicationContext继承了ListableBeanFactory和HierarchialBeanFactory,而ListableBeanFactoru和HiearachialBeanFactory都继承至BeanFactory,所以我们可以认为ApplicationContext继承了BeanFactory.不过,ApplicationContext比BeanFactory更加强大,ApplicationContext还继承了其它接口,也就表示了ApplicationContext还拥有其它功能,比如MessageSource表示国际化、ApplicationEventPublisher表示事件发布、EnvironmentCapable表示获取环境变量等.
在Spring的源码实现中,当我们new一个ApplicationContext的时候,其底层都会new一个BeanFactory出来,当使用ApplicationContext的某些方法的时候,比如getBean,底层会调用BeanFactory的getBean.
在Spring源码中,BeanFactory接口存在一个非常重要的实现类是DefaultListableBeanFactory.

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

DefaultListableBeanFactory类图

Spring核心概念 - 图1

  • AliasRegistry: 支持别名功能,一个名字可以对应多个别名
  • BeanDefitionRegistry: 可以注册、保存、移除、获取某个BeanDefinition
  • BeanFactory: Bean工厂,可以根据某个Bean的名字、或类型、或别名获取某个Bean对象
  • SingletonBeanRegistry: 可以直接注册、获取某个单例Bean
  • SimpleAliasRegistry: 实现了AliasRegistry接口中所定义的功能,支持别名功能
  • ListableBeanFactory: 在BeanFactory的基础上,增加了其它功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取到对应的beanNames,可以根据某个类型获取 类型与对应的Bean的映射关系
  • HierachicalBeanFactory: 在BeanFactory的基础上,添加了获取父BeanFactory的功能
  • DefaultSingletonBeanRegistry: 实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
  • ConfigurableBeanFactory: 在HierachicalBeanFactory和SingletonBeanRegistry的基础上添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器去进行类的加载)、设置Spring EL表达式解析器(表示BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
  • FactoryBeanRegistrySupport: 支持了FactoryBean的功能
  • AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配
  • AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNames
  • ConfigurableListableBeanFactory: 继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
  • AbstractAutowireCapableBeanFactory: 继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能
  • DefaultListableBeanFactory: 继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大

    ApplicationContext

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

  • HierarchicalBeanFactory: 拥有获取父BeanFactory的功能

  • ListableBeanFactory: 拥有获取beanNames的功能
  • ResourcePatternResolver: 资源加载器,可以一次性获取多个资源(文件资源等等)
  • EnvironmentCapable: 可以获取运行时环境(没有设置运行时环境功能)
  • ApplicationEventPublisher: 拥有广播事件的功能(没有添加事件监听器的功能)
  • MessageSource: 拥有国际化功能

    AnnotationConfigApplicationContext

    Spring核心概念 - 图2

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

  • AbstractApplicationContext: 实现了ConfigurableApplicationContext接口
  • GenericApplicationContext: 继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
  • AnnotationConfigRegistry: 可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
  • AnnotationConfigApplicationContext: 继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能

    ClassPathXmlApplicationContext

    Spring核心概念 - 图3
    它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition

    国际化

    定义MessageSource
      /**
       * 设置国际化
       */
      @Bean
      public MessageSource messageSource() {
          ResourceBundleMessageSource messageSource = new ResourceBundleMess
          messageSource.setBasename("messages");
          messageSource.setDefaultEncoding("utf8");
          return messageSource;
      }
    
    在resource目录下定义国际化文件messages_en_CN.properties、messages_en.properties messages_en_CN.properties
    fruit.apple=苹果
    
    messages_en.properties
    fruit.apple=apple
    
    进行使用国际化
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    String enCn = context.getMessage("fruit.apple", null, new Locale("en_CN"));
    System.out.println(enCn);
    
    苹果
    

    资源加载

    ApplicationContext还拥有资源加载的功能,比如: 可以直接利用ApplicationContext获取某个文件的内容 ```java AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource1 = context.getResource(“file:/Users/linc/Desktop/dev/codes/java/deep/spring-framework-5.3.10/linc-day01/src/main/java/linc/cool/config/AppConfig.java”); System.out.println(resource1.contentLength());

Resource resource2 = context.getResource(“https://www.baidu.com“); System.out.println(resource2.contentLength());

Resource resource3 = context.getResource(“classpath:spring.xml”); System.out.println(resource3.contentLength());

Resource[] resource4 = context.getResources(“classpath:linc/cool/*.class”); System.out.println(resource4.length);

<a name="BsCGz"></a>
## 获取运行时环境
```java
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Map<String, Object> sysEnvMap = context.getEnvironment().getSystemEnvironment();
System.out.println(sysEnvMap);
Map<String, Object> sysPropertiesMap = context.getEnvironment().getSystemProperties();
System.out.println(sysPropertiesMap);
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);
System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("Dfile.encoding"));

==注意==可以利用 在resource目录下加一个spring.properties的配置文件

NO_PROXY=yes

在配置类加上

@PropertySource("classpath:spring.properties")

事件发布

定义一个事件监听器

    /**
    * 事件监听器
    */
    @Bean
    public ApplicationListener<?> applicationListener() {
        return event -> {
            System.out.println("接收到一个事件: " + event);
        };
    }

然后发布一个事件

context.publishEvent("xxx");
@Component
public class MyPublishEventBean implements ApplicationContextAware {
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public void test() {
        context.publishEvent("myEvent");
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyPublishEventBean myPublishEventBean = context.getBean(MyPublishEventBean.class);
myPublishEventBean.test();

类型转化

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

PropertyEditor

PropertyEditor是JDK中提供的类型转化工具类

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("linc");
User user = (User) propertyEditor.getValue();
System.out.println(user);

如何向Spring中注册PropertyEditor

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

假设现在有一个Bean

@Component
public class UserService {

    @Value("linc")
    private User user;

    public void test() {
        System.out.println(user);
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService bean = context.getBean(UserService.class);
bean.test();

ConversionService

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

public class StringToUserConverter implements ConditionalGenericConverter {
    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
    }

    @Override
    public Set<ConvertiblePair> 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.valueOf(source));
        return user;
    }
}
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User user = conversionService.convert("linc", User.class);
System.out.println(user);

如何向Spring中注册ConversionService

/**
 * ConversionService类型转化
 */
@Bean
public ConversionServiceFactoryBean conversionService() {
    ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
    conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
    return conversionServiceFactoryBean;
}

TypeConverter

整合了PropertyEditor和ConversionService的功能是Spring内部用的

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor()
                                   User user = typeConverter.convertIfNecessary("linc", User.class);
                                   System.out.println(user);

OrderComparator

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

@ToString
public class A implements Ordered {
    @Override
    public int getOrder() {
        return 1;
    }
}
@ToString
public class B implements Ordered {
    @Override
    public int getOrder() {
        return 2;
    }
}
    A a = new A();
    B b = new B();
    OrderComparator comparator = new OrderComparator();
    System.out.println(comparator.compare(a, b));
    List<Object> 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)
@ToString()
public class C {
}
@Order(1)
@ToString()
public class D {
}
C c = new C();
D d = new D();
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
System.out.println(comparator.compare(c,d));
List<Object> list = new ArrayList<>();
list.add(c);
list.add(d);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // [D(), C()]

BeanPostProcessor

BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,可以处理初始化前或者初始化后的逻辑

@Component
public class MyBeanPostProcessor 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;
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService bean = context.getBean(UserService.class);
bean.test();

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

BeanFactoryPostProcessor

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程

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

FactoryBean

我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,我们可以使用FactoryBean

@Component
public class MyFactoryBean implements FactoryBean<UserService> {
    @Override
    public UserService getObject() throws Exception {
        return new UserService();
    }
    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }
}

我们自己创造了一个UserService,并且它将要成为Bean.但是通过这种方式创造出来的UserService的Bean,只会经历初始化后的逻辑,其他Spring的生命周期的步骤是不会经过的,比如说依赖注入.
通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?
@Bean定义的Bean是会经过完整的Bean生命周期的,而FactoryBean创建的对象只会经历初始化后的逻辑.

ExcludeFilter和IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的,ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器. 比如我们不想让UserService成为Bean

@ComponentScan(value = "linc.cool",
        excludeFilters = {@ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = UserService.class
        )}
)

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

@ComponentScan(value = "linc.cool",
        includeFilters = {@ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = UserService.class
        )}
)

FilterType分为:

  • ANNOTATION:表示是否包含某个注解
  • ASSIGNABLE_TYPE:表示是否是某个类
  • ASPECTJ:表示否是符合某个Aspectj表达式
  • REGEX:表示是否符合某个正则表达式
  • CUSTOM:自定义

    MetadataReader、ClassMetadata、AnnotationMetadata

    在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,比如类名、类中的方法、类上的注解这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类.
    MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader.
    SimpleMetadataReaderFactory factory = new SimpleMetadataReaderFactory();
    // 构造一个MetadataReader
    MetadataReader metadataReader = factory.getMetadataReader("linc.cool.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);
    }
    
    SimpleMetadataReader去解析类时,使用的ASM技术.
    为什么要使用ASM技术? Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术