【Spring 学习笔记】1.认识Spring 源码的一些基础类的

1. BeanDefinition

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

class,表示Bean类型
scope,表示Bean作用域,单例或原型等
lazyInit:表示Bean是否是懒加载
initMethodName:表示Bean初始化时要执行的方法
destroyMethodName:表示Bean销毁时要执行的方法
还有很多...

GenericBeanDefinition 是spring源码中BeanDefinition 常用的一个实现类;

extends
extends
GenericBeanDefinition
AnnotatedGenericBeanDefinition
ScannedGenericBeanDefinition

RootBeanDefinition 后续补充。。。

2. BeanDefinitionReader

  • AnnotatedBeanDefinitionReader

可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解
注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析为BeanDefinition,放入到Spring 容器中
annotatedBeanDefinitionReader.register(User.class);
  • XmlBeanDefinitionReader

可以解析标签

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml"); //Bean 配置文件
  • ClassPathBeanDefinitionScanner

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

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.test"); // 包路径

3. BeanFactory

3.1 BeanFactory 与 ApplicationContext的区别

ApplicationContext是,在Spring源码中,是如下代码定义的;

  • 我们发现 ApplicationContext 继承了 ListableBeanFactory和HierarchicalBeanFactory,而ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory, 可以认为ApplicationContext也是BeanFactory的一种,拥有BeanFactory支持的所有功能;
  • ApplicationContext比BeanFactory更加强大,ApplicationContext还继承了其他接口,也就表示ApplicationContext还拥有其他功能,比如MessageSource表示国际化,ApplicationEventPublisher表示事件发布,EnvironmentCapable表示获取环境变量,等等。
// ApplicationContext是,在Spring源码中,是这么定义的
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
            ...
}

3.2 DefaultListableBeanFactory

BeanFactory接口存在一个非常重要的核心的实现类。

// DefaultListableBeanFactory的用法
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 定义Bean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
// 用DefaultListableBeanFactory注册Bean
beanFactory.registerBeanDefinition("user", beanDefinition);

System.out.println(beanFactory.getBean("user"));

在这里插入图片描述
它实现了很多接口,表示,它拥有很多功能 (可以先简单了解一些)

  • AliasRegistry:支持别名功能,一个名字可以对应多个别名
  • BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
  • BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
  • SingletonBeanRegistry:可以直接注册、获取某个单例Bean
  • SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
  • ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
  • HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
    DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
  • ConfigurableBeanFactory:在HierarchicalBeanFactory和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的功能很强大

3.3 ApplicationContext

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

  • HierarchicalBeanFactory:拥有获取父BeanFactory的功能
  • ListableBeanFactory:拥有获取beanNames的功能
  • ResourcePatternResolver:资源加载器,可以一次性获取多个资源。(下边 3.3.2 的应用)
  • EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)(下边 3.3.2 的应用)
  • ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)(下边 3.3.4 的应用)
  • MessageSource:拥有国际化功能 (下边 3.3.3 的应用)

3.3.1 ApplicationContext两个比较重要的实现类:

都继承了AbstractApplicationContext,但ClassPathXmlApplicationContext相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition。

AnnotationConfigApplicationContext

在这里插入图片描述

ClassPathXmlApplicationContext

在这里插入图片描述

3.3.2 ApplicationContext 资源加载

  • 利用ApplicationContext获取某个文件的内容:
    代码示例:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\learning\\spring-framework-5.3.10\\src\\main\\java\\com\\zhouyu\\service\\tesrService.java");
System.out.println(resource.contentLength());
  • 利用ApplicationContext获取获取运行时环境
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取操作系统的环境变量
Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
// Java 运行指定的参数变量
Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
// 获取配置文件中的变量
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();

System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("zhouyu"));

3.3.3ApplicationContext 中的 MessageSource 国际化

3.3.4 事件发布

// 1. 先定义监听器--------------------------------------------------------------------------------------------------------------------------------
public class AppConfig {
	@Bean
	public ApplicationListener applicationListener() {
		return new ApplicationListener() {
			@Override
			public void onApplicationEvent(ApplicationEvent event) {
				System.out.println("接收到了一个事件");
			}
		};
	}
// 2. 定义事件发布--------------------------------------------------------------------------
@Component
public class PublishEventService implements ApplicationContextAware {
	private ApplicationContext applicationContext;
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	// 事件发布
	public void test(){
		applicationContext.publishEvent("test");
		System.out.println("发布成功");
	}
}
// 3 调用发布事件----------------------------------------------------------------------------------------------------------
	public static void main(String[] args) {

		// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		//调用发布事件
		PublishEventService publishEvent = (PublishEventService) applicationContext.getBean("publishEventService");
		publishEvent.test();
}

4 类型转化

在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 在源码的会遇到很多,提前熟悉类型转化能帮助更快速的解读源码。

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

代码应用

// 1 定义转化器
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);
	}
}
// 2 java 调用转化器 的方式
public static void main(String[] args){
	StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
		propertyEditor.setAsText("1");
		User value = (User) propertyEditor.getValue();
		System.out.println(value);
}
// 3 在spring的中调用的方式
	// 向Spring中注册PropertyEditor:
		public class AppConfig {
		@Bean
		public CustomEditorConfigurer customEditorConfigurer() {
			CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
			Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
			/*表示StringToUserPropertyEditor可以将String转化成User类型,
			 在Spring源码中,如果发现当前对象是String,而需要的类型是User,
			 就会使用该PropertyEditor来做类型转化*/
			propertyEditorMap.put(User.class, StringToUserPropertyEditor.class); // 重点步骤
			customEditorConfigurer.setCustomEditors(propertyEditorMap);
			return customEditorConfigurer;
		}
		}	
	// 可以在spring中如下调用
	@Component
	public class UserService {	
		@Value("name") // 此时设置user时会发现值是String,就会启用配置的类型转化类的设置
		private User user;	
		public void test() {
			System.out.println(user);
		}	
	}
  • Spring中提供的类型转化服务——ConversionService

代码应用

// 1. 定义自己的转类,实现ConditionalGenericConverter  接口
public class StringToUserConverter implements ConditionalGenericConverter {

	/**
	 * 定义转化匹配条件,如下当源类型是String,目标转化类型是User的时候才进行转化
	 */
	@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)source);
		return user;
	}
}
// 2 注册 CustomEditorConfigurer 
public class AppConfig {
	@Bean
	public ConversionServiceFactoryBean conversionService() {
		ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
		// 把自己定义的转化类设置进去
		conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
		return conversionServiceFactoryBean;
	}
}
// 3 业务逻辑中调用转化方法
{
	// 1. 实例化一个 类型转化服务器 conversionService
	DefaultConversionService conversionService = new DefaultConversionService();
	// 2. 将自己定义的转化类 StringToUserConverter 放入到conversionService
	conversionService.addConverter(new StringToUserConverter());
	// 3. 调用convert方法进行转化
	User value = conversionService.convert("1", User.class);
	System.out.println(value);
}
  • Spring中提供的类型转化服务——TypeConverter

  • 整合了PropertyEditor和ConversionService的功能,是Spring内部用的
    代码应用
{
		// 1. 实例化一个 typeConverter
		SimpleTypeConverter typeConverter = new SimpleTypeConverter();
		// 2. 设置自己定义的一个JDK PropertyEditor 转化器,StringToUserPropertyEditor
		typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
		// 2. 也可以设置自己定义的spring 类型转化器-conversionService, conversionService定义步骤参考上述
		//typeConverter.setConversionService(conversionService);
		// 3. 调用转化方法进去转换
		User value = typeConverter.convertIfNecessary("1", User.class);
		System.out.println(value.getName());
}

5 OrderComparator 比较器

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

实现Ordered接口 来执行比较

/* 测试类A*/
public class testA implements Ordered {

	@Override
	public int getOrder() {
		return 3;
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}

/* 测试类B*/
public class testB implements Ordered {

	@Override
	public int getOrder() {
		return 2;
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}

/* 运用 OrderComparator  比较器排序*/
public class Main {

	public static void main(String[] args) {
		A a = new A(); // order=3
		B b = new B(); // order=2

		OrderComparator comparator = new OrderComparator();
		System.out.println(comparator.compare(a, b));  // 1

		List list = new ArrayList<>();
		list.add(a);
		list.add(b);
		// 按order值升序排序
		list.sort(comparator);
		System.out.println(list);  // B,A
	}
}

根据@Order注解来执行比较

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

/* 测试类A*/
public class testA implements Ordered {
	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}

/* 测试类B*/
public class testB implements Ordered {
	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}

/* 运用 AnnotationAwareOrderComparator 比较器排序*/
public class Main {

	public static void main(String[] args) {
		A a = new A(); // order=3
		B b = new B(); // order=2

		AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
		System.out.println(comparator.compare(a, b)); // 1
		List list = new ArrayList<>();
		list.add(a);
		list.add(b);
	
		list.sort(comparator); // 按order值升序排序
		System.out.println(list); // B,A
	}
}

6 BeanPostProcessor Bean后置处理器

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

示例代码:

@Component
public class NingBeanPostProcessor 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;
	}
}

7 BeanFactoryPostProcessor Bean工厂后置处理器

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

示例代码:

@Component
public class NingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("加工beanFactory");
		// ...
	}
}

8 FactoryBean

可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的;
如果说BeanFactory是Bean 的自动化操作的话,FactoryBean 可以说是Bean的一定程度的手动操作模板,Spring在容器启动创建实例化Bean的时候,允许开发者有一定的权限来干涉自己所创建的Bean的条件;

通过FactoryBean获取Bean,代码示例:

@Component
public class NingFactoryBean implements FactoryBean {

	@Override
	public Object getObject() throws Exception {
		UserService userService = new UserService();
		return userService;
	}
	@Override
	public Class<?> getObjectType() {
		return UserService.class;
	}
}

// 获取Bean
public class ningApplication {

	public static void main(String[] args) {
		// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		System.out.println(applicationContext.getBean("ningFactoryBean")); // 获取的是 com.ning.service.UserService@7a92922
		System.out.println(applicationContext.getBean("&ningFactoryBean")); // 获取的是 com.ning.service.NingFactoryBean@2d6d8735
		}
}

@Bean生成一个对象作为Bean和FactoryBean的区别是什么呢?
很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。而FactoryBean 的Bean只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。

通过如下实验示例来体验一下:

// 1. 实现一个BeanPostProcessor ,看初始化前和后的两个方法调用情况
@Component
public class NingBeanPostProcesser implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if("ningFactoryBean".equals(beanName)){
			System.out.println("初始化前"+bean);
		}
		return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if("ningFactoryBean".equals(beanName)){
			System.out.println("初始化后"+bean );
		}
		return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
	}
}

// 2. 调用打印实验结果

public class ningApplication {

	public static void main(String[] args) {

		// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		System.out.println(applicationContext.getBean("ningFactoryBean")); 
		/* 实验结果如下,UserService Bean只会经历初始化后
		初始化前com.ning.service.NingFactoryBean@12bc6874
		初始化后com.ning.service.NingFactoryBean@12bc6874
		初始化后com.ning.service.UserService@77f03bb1*/
	}
}	

9 ExcludeFilter和IncludeFilter 过滤器

这两个Filter是Spring扫描过程中用来过滤的。
ExcludeFilter表示排除过滤器
FilterType分为:

  1. ANNOTATION:表示是否包含某个注解
  2. ASSIGNABLE_TYPE:表示是否是某个类
  3. ASPECTJ:表示否是符合某个Aspectj表达式
  4. REGEX:表示是否符合某个正则表达式
  5. CUSTOM:自定义

IncludeFilter表示包含过滤器
在spring进去扫码包的时候默认添加了一个包含过滤器,添加了@component的类默认会被扫描注册到Spring 容器中,这也是我们在编码的时候被@component注解注释的类会被注册到sipng容器

// Spring 中的源码
this.includeFilters.add(new AnnotationTypeFilter(Component.class)

过滤器的简单应用代码示例:

// 不去注册UserService.
@ComponentScan(value = "com.ning",
		excludeFilters = {@ComponentScan.Filter(
            	type = FilterType.ASSIGNABLE_TYPE, 
            	classes = UserService.class)}.)  // 排除UserService类
public class AppConfig {
}

// 不加注解也可以注册UserService.
@ComponentScan(value = "com.zhouyu",
		includeFilters = {@ComponentScan.Filter(
            	type = FilterType.ASSIGNABLE_TYPE, 
            	classes = UserService.class)})
public class AppConfig {
}

10 类的元数据,MetadataReader、ClassMetadata、AnnotationMetadata

Spring中对类的元数据(类名、类中的方法、类上的注解…等这些元数据信息)做了抽象,并提供了一些工具类,用于解析类的信息。

需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术。
为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不好,所以使用了ASM技术(并不把类加载到内存中,读取分析文件直接拿到这个文件资源去解析读取信息)。

// 元数据类的简单应用代码
public class Test {
	public static void main(String[] args) throws IOException {
		SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
		
        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.zhouyu.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);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值