spring源码篇(二)核心概念熟悉

5 篇文章 0 订阅

spring核心概念

spring中的几个核心概念,在看源码前先了解这些概念,后面再去看源码会更容易理解源码。

1. beanDefinition

bean的抽象对象,它存储着一个bean对象的各种信息,如class信息、beanName、作用范围scope等信息;spring启动时,会扫描class字节码文件,然后将这些类都存储为beanDefinition,第一次扫描之后,得到所有的bean定义,之后就开始bean的初始化等等操作,所以可以把beanDefinition理解为原材料,spring为包工头,用这些原材料创建,重组完成项目基础架构的建造,所谓兵马未动粮草先行,在spring初始化容器创建bean时,就是根据这些beanDefinition进行实例化的。

定义bean的方式:

  1. <bean/>
  2. @Bean
  3. @Component/@Service/@Controller…

使用上面的方式去定义一个bean时,实际上底层spring是有去做解析,并生成beanDefinition这个对象,之后再通过这个对象生成对应的实例化对象,并不会直接生成一个实例化对象,这个联系之后的篇章会更好理解,这里只对概念进行说明。

那么我们指定spring是实例化对象是通过beanDefinition来创建的,所以,我们也可以手动创建一个beanDefinition,然后让spring生成一个,如下代码:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

// 定义一个beanDefinition,实际类型为MenuService,并且是单例对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(MenuService.class);
beanDefinition.setScope("singleton");
// 将自定义的beanDefinition注册到容器中
applicationContext.registerBeanDefinition("MenuService", beanDefinition);
// 通过getBean获取我们定义的类型的实例对象,这个方法在获取实例对象时,如果没有这个对象,就会创建
MenuService bean = applicationContext.getBean(MenuService.class);
// 打印该对象的内存地址
System.out.println(bean);

image-20210227215910124

2. beanDefinitionReader

beanDefinition的读取器,用于注册beanDefinition, 提供了注册、获取资源加载器、获取类加载器、beanname生成、加载beanDefinition等接口。

对应eanDefinition定义方式,它也有2种读取方式:

  • XmlBeanDefinitionReader:扫描<bean/>标签
  • AnnotatedBeanDefinitionReader:扫描由注解定义的类,能够解析的注解:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

还有一个读取方式,就是ClassPathBeanDefinitionScanner,和上面两个一样,多了一个路径扫描,并将扫描到的含有注解的类注册

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// 扫描xml注册bean
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(beanFactory);
		int i = xmlReader.loadBeanDefinitions("spring.xml");
		Object userService = beanFactory.getBean("userService");
		System.out.println(userService);

		// 扫描配置类 注册bean
		AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(applicationContext);
		reader.register(MenuService.class);
		MenuService bean = applicationContext.getBean(MenuService.class);
		System.out.println(bean);

		// 扫描类路径 注册
		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
		int scan = scanner.scan("com.lry.service");
		Object userService2 = beanFactory.getBean("userService");
		System.out.println(userService2);

3. beanFactory

beanFactory有存放bean,生成bean的功能,但它只是一个接口,spring中最核心的是DefaultListableBeanFactory,它是beanFactory最底层的类,获取beanDefinition、注册beanDefinition、别名功能、bean注册、获取bean、自动装配功能等等,也就是管理bean的容器。

如下图,每一个接口都表示着它所拥有的能力:

image-20210228005031763

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

4. ApplicationContext

首先ApplicationContext不止继承了beanFactory,还有registry、resourceLoader等,可以完成资源加载、解析、注册bean、获取bean等功能。

image-20210228103244062

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

5. AnnotationConfigApplicationContext

image-20210228102624588

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

  2. AbstractApplicationContext:实现了ConfigurableApplicationContext接口

  3. GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)

  4. AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的**@Configuration注解**,已经可以处理**@Bean注解**),同时可以扫描

  5. AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能

  6. AutoCloseable:资源关闭

  7. Lifecycle:回调类

6. ClassPathXmlApplicationContext

这个功能比起AnnotationConfigApplicationContext没有注册beanDefinition功能。

7. 国际化

可配置国际通用的配置,配置格式:文件基础名称_语言.properties

// 这种文件基础名称	
@Bean
	public MessageSource messageSource() {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		// 设置基础名称
		messageSource.setBasename("message");
		// 需要加上这个编码,不然读出来的是乱码(编码根据文件的编码格式设置)
		messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
		return messageSource;
	}
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 通过key或对应信息
// 这里的Locale设置语言,有提供默认的,也可以自己设置:new Locale("文件后缀")
String message = applicationContext.getMessage("key", null, Locale.ENGLISH);
		System.out.println(message);
		System.out.println(applicationContext.getMessage("key", null, Locale.CHINESE));;

上述代码读取的文件是/resource/message_zh_ch.properties,是在resource下的,没有文件夹;
当然,文件命名不会这么死板的叫zh_ch,也可以是其他的,如message_zhong.properties,都是可以设置的:

		System.out.println(applicationContext.getMessage("key", null, new Locale("zhong")));;

8. 资源加载

Resource resource = applicationContext.getResource("spring.xml");
System.out.println(resource.getFilename());
System.out.println(applicationContext.getResource("file:E:\\Program File\\work\\workspace\\other_people\\spring-framework2\\luban\\src\\main\\java\\com\\lry"));
		

9. 运行时环境

可以做到如下的操作

// 获取JVM所允许的操作系统的环境
annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();

// 获取JVM本身的一些属性,包括-D所设置的
annotationConfigApplicationContext.getEnvironment().getSystemProperties();

// 还可以直接获取某个环境或properties文件中的属性
annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")
@Component
@ConfigurationProperties(prefix = "test")
@PropertySource(value = {"classpath:pro.properties"})
//@PropertySource(value = {"file:E:/pro.properties"})
public class TestClass {

    @Value("${test.name}")
    private String name;

    @Value("${test.age}")
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

10. 事件发布

@Bean
public ApplicationListener applicationListener() {
    return new ApplicationListener() {
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            System.out.println("接收到了一个事件");
        }
    };
}
applicationContext.publishEvent("ss");

这里出现两次打印,是因为在spring启动完后会有一次,然后我手动调用一次,一共两次

image-20210228134451765

11. 类型转化

PropertyEditor

jdk提供的工具类,PropertyEditor看名字就知道,将spring转化为对象

public class CustomPropertyEditor extends PropertyEditorSupport implements PropertyEditor {

	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		User user = new User();
		user.setName(text);
		this.setValue(user);
	}
}

继承了PropertyEditorSupport

CustomPropertyEditor editor = new CustomPropertyEditor();
editor.setAsText("测试");
Object value = editor.getValue();
System.out.println(((User)value).getName());

ConversionService

对比PropertyEditor,功能更多

public class CustomConvertor 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("ceshi");
		return user;
	}
}
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new CustomConvertor());
User ceshi = conversionService.convert("ceshi", User.class);
System.out.println(ceshi.getName());

TypeConverter

这个转换器整合了PropertyEditorConversionService的功能

// 将value转化为requiredType类型
convertIfNecessary(Object value, Class<T> requiredType) 
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new CustomPropertyEditor());
User user = typeConverter.convertIfNecessary("ceshi", User.class);
System.out.println(user.getName());

12. BeanPostProcessor

bean的后置处理器,可以在创建每个Bean的过程中进行干涉,如在bean的实例化前或后,修改bean,或者做一些处理,如aop

13. BeanFactoryPostProcessor

bean工厂的后置处理器,可以对beanFactory继续设置,比如修改beanFactory的属性,增加xml方式注入的忽略接口等。

14. FactoryBean

它和beanFactory不一样,首先factoryBean可以注册成为一个bean,而它的子类更是添加了获取bean工厂的接口,如AbstractFactoryBean,继承子类你就有了bean工厂的功能。

理解的话,有点像工厂模式,用于生产某个bean的,它的getObject方法只调用一次。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值