博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring中核心概念详解(看源码必备)
阅读量:2289 次
发布时间:2019-05-09

本文共 10284 字,大约阅读时间需要 34 分钟。

BeanDefinition

Bean的定义,在Spring中,我们可以如何去定义一个Bean?

  1. <bean/>
  2. @Bean
  3. @Component(@Service,@Controller)

 

还有就是可以通过BeanDefinition

 

比如,我们可以通过定义一个BeanDefinition对象来表示定义了一个Bean:

// 定义了一个BeanDefinitionAbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();// 当前Bean对象的类型beanDefinition.setBeanClass(User.class);// 将BeanDefinition注册到BeanFactory中DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();beanFactory.registerBeanDefinition("user", beanDefinition);// 获取BeanSystem.out.println(beanFactory.getBean("user"));

我们还可以通过BeanDefinition设置一个Bean的其他属性

beanDefinition.setScope("prototype"); // 设置作用域beanDefinition.setInitMethodName("init"); // 设置初始化方法beanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); // 设置自动装配模型

等等

 

总之,我们通过<bean/>,@Bean,@Component等方式所定义的Bean,最终都会被解析为BeanDefinition对象。

 

BeanDefinition可以理解为底层源码级别的一个概念,也可以理解为Spring提供的一种API使用的方式。

 

 

BeanDefinitionReader

 

BeanDefinitionReader分为几类:

 

AnnotatedBeanDefinitionReader

 

可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解

 

注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

 

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory);// 将User.class解析为BeanDefinitionannotatedBeanDefinitionReader.register(User.class);System.out.println(beanFactory.getBean("user"));

 

XmlBeanDefinitionReader

 

可以解析<bean/>标签

 

XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");System.out.println(beanFactory.getBean("user"));

 

ClassPathBeanDefinitionScanner

 

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

 

BeanFactory

 

Spring中比较核心的是BeanFactory的实现类是DefaultListableBeanFactory

 

image.png

它实现了很多接口,表示,它拥有很多功能:

  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的功能很强大

 

通过以上分析,我们可以知道,通过DefaultListableBeanFactory我们可以做很多事情,比如:

 

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(User.class);DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 注册BeanDefinitionbeanFactory.registerBeanDefinition("user", beanDefinition);// 注册别名beanFactory.registerAlias("user", "user1");// 注册BeanPostProcessorbeanFactory.addBeanPostProcessor(new LubanBeanPostProcessor());// 获取Bean对象System.out.println(beanFactory.getBean("user1"));// 根据类型获取beanNamesSystem.out.println(beanFactory.getBeanNamesForType(User.class));

 

ApplicationContext

 

首先ApplicationContext是个接口,可以把它理解为一个特殊的BeanFactory

image.png

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

 

 

 

又两个比较重要的实现类:

  1. AnnotationConfigApplicationContext
  2. ClassPathXmlApplicationContext

 

AnnotationConfigApplicationContext

image.png

 

  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接口,拥有了以上所有的功能

 

ClassPathXmlApplicationContext

image.png

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

 

 

国际化

先定义一个MessageSource:

@Beanpublic MessageSource messageSource() {    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();    messageSource.setBasename("messages");    return messageSource;}

有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。

同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:

annotationConfigApplicationContext.getMessage("test", null, new Locale("en_CN"))

 

资源加载

ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:

Resource resource = annotationConfigApplicationContext.getResource("file://D:\\IdeaProjects\\spring-framework\\luban\\src\\main\\java\\com\\luban\\entity\\User.java");System.out.println(resource.contentLength());

你可以想想,如果你不使用ApplicationContext,而是自己来实现这个功能,就比较费时间了。

 

还比如你可以:

Resource resource = annotationConfigApplicationContext.getResource("classpath:com/luban/entity/User.class");System.out.println(resource.contentLength());

 

还可以一次性获取多个:

Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/luban/service/*.class");for (Resource resource : resources) {    System.out.println(resource.contentLength());}

 

这个功能用到了策略模式

获取运行时环境

 

// 获取JVM所允许的操作系统的环境annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();// 获取JVM本身的一些属性,包括-D所设置的annotationConfigApplicationContext.getEnvironment().getSystemProperties();// 还可以直接获取某个环境或properties文件中的属性annotationConfigApplicationContext.getEnvironment().getProperty("lubanyyy")

注意,可以利用

@PropertySource("classpath:application.properties")

来使得某个properties文件中的参数添加到运行时环境中

 

 

事件发布

先定义一个事件监听器

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

 

然后发布一个事件:

annotationConfigApplicationContext.publishEvent("kkk");

 

 

类型转化

PropertyEditor

JDK中提供的类型转化工具类

 

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

 

StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();propertyEditor.setAsText("1");User value = (User) propertyEditor.getValue();System.out.println(value);

 

如何向Spring中注册PropertyEditor:

@Beanpublic CustomEditorConfigurer customEditorConfigurer() {    CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();    Map
, Class
> propertyEditorMap = new HashMap<>(); propertyEditorMap.put(User.class, StringToUserPropertyEditor.class); customEditorConfigurer.setCustomEditors(propertyEditorMap); return customEditorConfigurer;}

 

假设现在有如下Bean:

@Componentpublic class UserService {    @Value("true")    User test;    public void test() {        System.out.println(test);    }}

那么test属性就能正常的完成属性赋值

 

 

ConversionService

Spring中提供的类型转化服务,它比PropertyEditor更强大

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
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; }}
DefaultConversionService conversionService = new DefaultConversionService();conversionService.addConverter(new StringToUserConverter());User value = conversionService.convert("1", User.class);System.out.println(value);

 

如何向Spring中注册ConversionService:

@Beanpublic ConversionServiceFactoryBean conversionService() {    ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();    conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));    return conversionServiceFactoryBean;}

 

TypeConverter

整合了PropertyEditor和ConversionService的功能,是Spring内部用的

SimpleTypeConverter typeConverter = new SimpleTypeConverter();typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());//typeConverter.setConversionService(conversionService);User value = typeConverter.convertIfNecessary("1", User.class);System.out.println(value);

 

BeanPostProcessor

Bean的后置处理器,可以在创建每个Bean的过程中进行干涉,是属于BeanFactory中一个属性,讲Bean的生命周期中详细讲。

 

BeanFactoryPostProcessor

Bean工厂的后置处理器,是属于ApplicationContext中的一个属性,是ApplicationContext在实例化一个BeanFactory后,可以利用BeanFactoryPostProcessor继续处理BeanFactory。

 

程序员可以通过BeanFactoryPostProcessor间接的设置BeanFactory,比如上文中的CustomEditorConfigurer就是一个BeanFactoryPostProcessor,我们可以通过它向BeanFactory中添加自定义的PropertyEditor。

FactoryBean

 

允许程序员自定义一个对象通过FactoryBean间接的放到Spring容器中成为一个Bean。

 

那么它和@Bean的区别是什么?因为@Bean也可以自定义一个对象,让这个对象成为一个Bean。

 

区别在于利用FactoryBean可以更加强大,因为你通过定义一个XxFactoryBean的类,可以再去实现Spring中的其他接口,比如如果你实现了BeanFactoryAware接口,那么你可以在你的XxFactoryBean中获取到Bean工厂,从而使用Bean工厂做更多你想做的,而@Bean则不行。

 

转载地址:http://ibbnb.baihongyu.com/

你可能感兴趣的文章
iar注释快捷键
查看>>
ubuntu16.04 okular中文界面
查看>>
Intel Core系列CPU架构演变
查看>>
同步,异步 and 阻塞,非阻塞
查看>>
os, sys模块及其他内容
查看>>
谷歌:1024!的末尾有多少个零
查看>>
微软、谷歌、百度等公司经典面试100题[第101-160题]
查看>>
微软、Google等公司的面试题及解答、第161-170题
查看>>
九月十月百度人搜,阿里巴巴,腾讯华为小米搜狗笔试面试八十题(2012年度笔试面试八十题)
查看>>
十月百度,阿里巴巴,迅雷搜狗最新面试七十题(第201-270题)(2011年度十月上旬七十题)
查看>>
Linux xargs 用法详解
查看>>
scp:windows与linux之间copy文件(类似于linux的scp工具)
查看>>
编程艺术第十六~第二十章:全排列/跳台阶/奇偶调序,及一致性Hash算法
查看>>
程序员编程艺术第三十九~四十章:最近公共祖先LCA、打印螺旋矩阵
查看>>
程序员编程艺术第十一章:最长公共子序列(LCS)问题
查看>>
程序员编程艺术:第二章、字符串是否包含问题
查看>>
程序员编程艺术:第三章、寻找最小的k个数
查看>>
程序员编程艺术:第三章续、Top K算法问题的实现
查看>>
程序员编程艺术第一~十章集锦与总结(教你如何编程)--持续更新中
查看>>
程序员编程艺术:第四章、现场编写类似strstr/strcpy/strpbrk的函数
查看>>