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。