spring底层核心概念解析

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。

posted @ 2022-11-12 22:08  StudyHardWork  阅读(41)  评论(0编辑  收藏  举报