> 文档中心 > Spring核心概念

Spring核心概念


Spring核心概念

  • BeanDefinition
  • BeanDefinitionReader
  • ClassPathBeanDefinitionScanner
  • ApplicationContext
  • 国际化
  • 资源加载
  • 获取运行环境
  • 事件发布
  • 类型转化
  • OrderComparator
  • BeanPostProcessor
  • BeanFactoryPostProcessor
  • FactoryBean
  • ExcludeFilter、IncludeFilter
  • MetadataReader、ClassMetadata、AnnotationMetadata

BeanDefinition

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

比如:

  • class: 表示bean类型
为什么这里是Object,而不是Class<?>?因为这里还没有加载,只是通过ASM技术去解析了这个类,并没有去解析,只是把这个类的名字设置给了BeanDefinition的属性,当创建这个Bean的时候,才会去真正的加载,所以这里使用的是Objectprivate volatile Object beanClass;
  • scope: 表示bean作用域,有single、prototype、request、session、global
  • lazyInit: 表示Bean是否是懒加载的
  • initMethodName: 表示Bean初始化时要执行的方法
  • destoryMethodName: 表示Bean销毁时要执行的方法
  • 等等
    在Spring中,我们经常会通过声明式定义Bean:
  • bean标签
  • @Bean
  • @Component、@Service、@Controller
    我们也可以使用编程式定义Bean,那就是直接通过BeanDefinition
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 生成一个beanDefinitionAbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();// 设置beanClassbeanDefinition.setBeanClass(User.class);// 设置作用域beanDefinition.setScope("prototype");// 设置初始化方法beanDefinition.setInitMethodName("init");// 设置是否懒加载beanDefinition.setLazyInit(true);// 注册beanDefinitioncontext.registerBeanDefinition("user", beanDefinition);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解析成BeanDefinitionreader.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都继承至BeanFacorY,所以我们可以认为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核心概念

  • 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核心概念

  • ConfigurableApplicationContext: 继承了ApplicationContext接口,增加了添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取 ConfigurableListableBeanFactory等功能
  • AbstractApplicationContext: 实现了ConfigurableApplicationContext接口
  • GenericApplicationContext: 继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
  • AnnotationConfigRegistry: 可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
  • AnnotationConfigApplicationContext: 继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能

ClassPathXmlApplicationContext

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

国际化

定义MessageSource

/** * 设置国际化 */@Beanpublic MessageSource messageSource() {ResourceBundleMessageSource messageSource = new ResourceBundleMessmessageSource.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获取某个文件的内容

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);

获取运行时环境

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")

事件发布

定义一个事件监听器

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

然后发布一个事件

context.publishEvent("xxx");
@Componentpublic class MyPublishEventBean implements ApplicationContextAware {private ApplicationContext context;@Overridepublic 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 {@Overridepublic 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

    /** * 类型转化 */@Beanpublic 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

@Componentpublic 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 {@Overridepublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);}@Overridepublic Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(String.class, User.class));}@Overridepublic 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类型转化 */@Beanpublic 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接口来执行值进行比较,从而可以进行排序

@ToStringpublic class A implements Ordered {@Overridepublic int getOrder() {return 1;}}
@ToStringpublic class B implements Ordered {@Overridepublic 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,可以处理初始化前或者初始化后的逻辑

@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("初始化前");}return bean;}@Overridepublic 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的创建过程

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

FactoryBean

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

@Componentpublic class MyFactoryBean implements FactoryBean<UserService> {@Overridepublic UserService getObject() throws Exception {return new UserService();}@Overridepublic 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();// 构造一个MetadataReaderMetadataReader 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技术