首页 > 其他分享 >spring底层核心概念解析

spring底层核心概念解析

时间:2022-11-12 22:11:59浏览次数:39  
标签:spring System class println new 解析 out public 底层

1.BeanDefinition

包含bean的一些基本元信息,如bean的类型,作用域,初始化方法...等等。

  • 申明式的定义,如@Bean,等等
<bean class="com.test.service.UserService" id="userService" scope="prototype"/>
  • 编程式的定义一个bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(UserService.class);
        beanDefinition.setScope("prototype");
        beanDefinition.setInitMethodName("");
        ...
      //注册到context中
        applicationContext.register("userService",beanDefinition);

2.AnnotatedBeanDefinitionReader

spring提供了类似的BeanDefinition的读取器工具类,将一个类注册到context中作为一个Bean对象。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader beanDefinitionReader=new AnnotatedBeanDefinitionReader(applicationContext);
beanDefinitionReader.registerBean(User.class);

      传入的User类将被读取作为一个BeanDefinfition放到spring容器中,注册时回去解析判断类上的注解,如@Lazy等等。

类似的Reader还有XmlBeanDefinitionReader来解析xml文件bean标签,ClassPathBeanDefinitionScanner来扫描包**

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

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

3.BeanFactory

bean工厂,负责创建bean,并提供获取bean的api。

ApplicationContext是BeanFactory的一种。且ApplicationContext继承了其他的接口,如事件发布器,获取环境变量,国际化等等。

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

  • AliasRegistry:别名的功能,若一个类继承了AliasRegistry接口,则一个bean可以有多个名字。基于此类图可以实现自己的BeanFactory,需要那些功能,则继承哪些接口。

  • HierarchiacalBeanFactory:支持父子bean工厂,可获取父BeanFactory,在两个bean工厂中,在其中一个bean工厂getBean时get不到,若继承此接口,则可以去父bean工厂getBean。

4.ApplicationContext下的国际化:MessageResoure,ApplicationContext实现了MessageSource接口,说明ApplicationContext是拥有国际化的而功能。

  • 新建messageResource文件夹,实现默认语言和英文:

定义MeaasgeSource的Bean。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		System.out.println(applicationContext.getMessage("苹果",null,new Locale("en")));

在自己的bean中的相关实现:

@Component
public class UserService implements ApplicationContextAware {

	private ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext=applicationContext;
	}
	
	public void test(){
		applicationContext.getMessage(...);
		...
	}
}

5.ApplicationContext下的资源加载功能,如文件资源,网络资源等等。

直接利用ApplicationContext获取某个文件的功能

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework-5.3.10\\src\\main\\java\\com\\test\\service\\UserService.java");
System.out.println(resource.contentLength());

还可以

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework-5.3.10\\src\\main\\java\\com\\test\\service\\UserService.java");
System.out.println(resource.contentLength());
System.out.println(resource.getFilename());

Resource resource1 = context.getResource("https://www.baidu.com");
System.out.println(resource1.contentLength());
System.out.println(resource1.getURL());

Resource resource2 = context.getResource("classpath:spring.xml");
System.out.println(resource2.contentLength());
System.out.println(resource2.getURL());

6,ApplicationContext获取运行时环境,操作系统层面的环境变量。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

//操作系统层面的环境变量
Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);

//运行时指定的-D的环境变量,如encoding
Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);


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

还可以通过@PropertySource("classpath:spring.properties")获取配置文件中的属性

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

MutablePropertySources propertySources1 = applicationContext.getEnvironment().getPropertySources();

7.ApplicationContext下的事件发布器

  • 定义一个事件监听器
@Bean
public ApplicationListener applicationListener() {
	return new ApplicationListener() {
		@Override
		public void onApplicationEvent(ApplicationEvent event) {
			System.out.println("接收到了一个事件");
		}
	};
}
  • 发布一个事件
context.publishEvent("aaa");

8.类型转换相关

1.PropertyEditor

将一个String类型的字符串转换成指定的类型,如

@Component
public class UserService {

	@Value("xxx")
	private User user;

	public void test() {
		System.out.println(user);
	}

}

或在配置文件中的<bean class="" id="">

实现:

  • 编写自己的转换器,实现PropertyEditor接口
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);
	}
}
  • 想spring注册PropertyEditor
@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;
}
  • 输出
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);

2.ConversionService

功能更加强大,可指定转换的类型。

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)source);
		return user;
	}
}
  • 向spring注册ConversionService
@Bean
public ConversionServiceFactoryBean conversionService() {
	ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
	conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

	return conversionServiceFactoryBean;
}
  • 输出测试
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);

9.比较器OrderComparator

OrderComparator可以根据@Order注解或者实现了Ordered接口的进行比较,根据order执行的值,从而可以进行排序。

public class A implements Ordered {

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

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}
public class B implements Ordered {

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

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}
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
	}
}

10.BeanPostProcessor

bean的后置处理器,在任意一个bean(也可以指定判断某个bean)的初始化前后执行bean的初始化前方法和初始化后方法,从而去执行用户的一些自定义逻辑。

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

11.元数据读取器,MetadataReader、ClassMetadata、AnnotationMetadata

spring中去解析类的的相关信息,如类名,方法,注解等等,都可成为类的元数据,spring对这些信息做了一些抽象,并提供一些工具类

1.MetadataReader,元数据读取器,默认实现为SimpleMetadataReader

public class Test {

	public static void main(String[] args) throws IOException {
	SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();

		// 构造一个MetadataReader
		MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.test.service.UserService");

		// 得到一个ClassMetadata,并获取了类名
		ClassMetadata classMetadata = metadataReader.getClassMetadata();

		System.out.println(classMetadata.getClassName());
		System.out.println(classMetadata.getInterfaceNames());//获取类的接口的名字
		System.out.println(classMetadata.getMemberClassNames());//获取内部类的名字

		// 获取一个AnnotationMetadata,并获取类上的注解信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		for (String annotationType : annotationMetadata.getAnnotationTypes()) {
			System.out.println(annotationType);
		}
	}
}

MetadataReader传入一个类的全路径,解析这个类时使用的是ASM技术,当使用某个类时,jvm才去加载某个类,ASM避免当指定的包路劲比较广时,将这些类一次性全部加载进JVM。

标签:spring,System,class,println,new,解析,out,public,底层
From: https://www.cnblogs.com/huang580256/p/16882399.html

相关文章

  • 【SpringBoot】分布式RPC+Zokeeper+SpringBoot练手
    RPCRPC两个核心模块:通讯,序列化序列化:数据传输需要转换DubboApacheDubbo|ˈdʌbəʊ|是一款高性能、轻量级的开源JavaRPC框架,它提供了三大核心能力:面向接口的远程......
  • # SpringBoot 整合 Swagger
    SpringBoot整合Swagger是什么不介绍,这个东西很简单,主要看点底层源码即可,注意:这个东西很容易造成版本错乱的部分引入狂神说的代码段,因为我有些东西懒得写引入<sp......
  • Spring set注入-级联属性赋值
    举例说明:有一个Student类,一个Clazz类。StudentpublicclassStudent{privateStringname;//学生属于哪个班级privateClazzclazz;//使......
  • 设计模式学习(二十四):Spring 中使用到的设计模式
    设计模式学习(二十四):Spring中使用到的设计模式作者:Grey原文地址:博客园:设计模式学习(二十四):Spring中使用到的设计模式CSDN:设计模式学习(二十四):Spring中使用到的设计模式......
  • 【SpringBoot】必须掌握的45个注解
    1、SpringBoot/spring@SpringBootApplication:包含@Configuration、@EnableAutoConfiguration、@ComponentScan通常用在主类上;@Repository:用于标注数据访问组件,即DAO组件......
  • 11-SpringBoot2整合Vue最简入门
    vuejs入门环境搭建》1:导入文件<scripttype="text/javascript"src="js/vue.js"></script><scripttype="text/javascript"src="js/axios.js"></script>》2:准备app视......
  • 08-SpringBoot2.0 集成 mybatis注解开发***
    1,依赖pom.xml<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><versi......
  • SpringBoot(二):创建SpringBoot项目的方式
    一、通过官网进行创建官网创建链接:https://start.spring.io/1.官网页面配置: Project:我们需要选择项目类型,我使用的是Maven项目;Language:使用的是Java语言,选择Java;Sp......
  • SpringBoot+Vue实现excel导入带格式化的时间参数(moment格式化明天日期并设置el-date-
    场景若依管理系统前后端分离版基于ElementUI和SpringBoot怎样实现Excel导入和导出:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108278834在上面进行Ex......
  • SpringBoot(一):初步认识SpringBoot
    一、SpringBoot是什么 在了解SpringBoot之前,我们需要先来回顾一下Spring。Spring是一个轻量级的WEB应用开发的框架,它的初衷是为了简化企业级应用开发的复杂性,说白了就是......