本篇文章将对Spring底层的一些概念做一些简单的分析 , 也是为了方便后续在阅读源码的时候更加的方便

BeanDefintion

BeanDefintion是一个接口 , 它表示一个Bean的定义 , BeanDefintion存在很多属性来描述一个Bean的特点 , Spring在扫描完需要注册的Bean之后会进行解析 , 而解析的数据就会存入到BeanDefintion
我们在定义Bean的时候可以分为两种方式 :

申明式

申明式定义一个Bean就比如我们用的@Bean , @Component等注解 , 或者是xml标签的形式来定义一个Bean

编程式

编程式就是通过写代码的方式来定义 , 如下
首先定义一个MenberService

public class MemberService {public void test(){System.out.println("test方法被调用...");}}

接着我们从Spring获取这个’Bean’ , 看是否能获取到

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);MemberService memberService = (MemberService) applicationContext.getBean("memberService");memberService.test();}}

运行之后我们回发现报错了 , 报错内容如下 :

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘memberService’ available
没有找到一个名为memberService的Bean来使用

我们再用编程式的方式定义

public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 得到一个BeanDefinition对象AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();// 设置Bean的类型beanDefinition.setBeanClass(MemberService.class);// 设置Bean的作用域beanDefinition.setScope("prototype");// 当然光这样申明还是不够的 , 我们需要调用一个函数来把这个beanDefinition注册到容器中 , 在注册的时候我们可以指定一个Bean的名称applicationContext.registerBeanDefinition("memberService" , beanDefinition);MemberService memberService = (MemberService) applicationContext.getBean("memberService");memberService.test();}}

接着运行进行测试 , 会发现这次并没有报错 , 并且也打印出来了 “test方法被调用…”
其实不难理解 , 我们通过注解的方式去定义 , 当Spring扫描完解析的时候 , 他底层也会把解析的结果封装到BeanDefinition, 我们现在不通过注解申明的方式 , 而是直接编程式的把值封装到BeanDefinition中 , 然后注册到Spring容器 , 这样我们就可以使用了

BeanDefinitionReader

现在我们介绍几种BeanDefintion的几种读取器 , 虽然在工作中用的很少 , 但是 , 它也是Spring基础设施中比较重要的一部分

AnnotatedBeanDefinitionReader

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

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 把某一个类转换为BeanDefinition之后 , 我们也需要将它注册到Spring容器中 , 所以需要传一个ApplicationContext对象AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);// 注册到Spring容器中annotatedBeanDefinitionReader.register(MemberService.class);MemberService memberService = (MemberService) applicationContext.getBean("memberService");memberService.test();}}

运行测试发现控制台打印 ” test方法被调用…” , 我们可以简单看一下register()方法

public void register(Class<?>... componentClasses) {for (Class<?> componentClass : componentClasses) {registerBean(componentClass);}}
public void registerBean(Class<?> beanClass) {doRegisterBean(beanClass, null, null, null, null);}
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,@Nullable BeanDefinitionCustomizer[] customizers) {AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(supplier);// 解析@Scope注解的结果为ScopeMetadataScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);// 将类的作用域添加到数据结构中abd.setScope(scopeMetadata.getScopeName());String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}if (customizers != null) {for (BeanDefinitionCustomizer customizer : customizers) {customizer.customize(abd);}}BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}

我们看一下processCommonDefinitionAnnotations()方法

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {processCommonDefinitionAnnotations(abd, abd.getMetadata());}
// 处理@Lazy、@Primary、@DependsOn、@Role、@Descriptionstatic void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);if (lazy != null) {abd.setLazyInit(lazy.getBoolean("value"));}else if (abd.getMetadata() != metadata) {lazy = attributesFor(abd.getMetadata(), Lazy.class);if (lazy != null) {abd.setLazyInit(lazy.getBoolean("value"));}}if (metadata.isAnnotated(Primary.class.getName())) {abd.setPrimary(true);}AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);if (dependsOn != null) {abd.setDependsOn(dependsOn.getStringArray("value"));}AnnotationAttributes role = attributesFor(metadata, Role.class);if (role != null) {abd.setRole(role.getNumber("value").intValue());}AnnotationAttributes description = attributesFor(metadata, Description.class);if (description != null) {abd.setDescription(description.getString("value"));}}

可以看到 , 他底层的逻辑代码和我们刚刚用编程式定义的方式差不多 , 也是创建一个BeanDefintion对象 , 然后解析注解并设置BeanDefintion的值 , 那么这个AnnotatedBeanDefinitionReader读取器在什么时候用的呢?其实是在创建AnnotationConfigApplicationContext容器对象时候用的 , 我们点进去看一下它的构造方法

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScannerthis();// 注册bean配置类register(componentClasses);// 刷新上下文refresh();}

然后看this()方法

public AnnotationConfigApplicationContext() {StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");// 额外会创建StandardEnvironmentthis.reader = new AnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner = new ClassPathBeanDefinitionScanner(this);}

我们就可以看到它构造了一个AnnotatedBeanDefinitionReader对象 , 其实Spring容器本身也有register()方法

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);applicationContext.register();

其实它们使用的是同一个方法 , 看一看applicationContext.register()方法的源码

@Overridepublic void register(Class<?>... componentClasses) {Assert.notEmpty(componentClasses, "At least one component class must be specified");StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register").tag("classes", () -> Arrays.toString(componentClasses));this.reader.register(componentClasses);registerComponentClass.end();}
public void register(Class<?>... componentClasses) {for (Class<?> componentClass : componentClasses) {registerBean(componentClass);}}
public void registerBean(Class<?> beanClass) {doRegisterBean(beanClass, null, null, null, null);}

可以看到, 它们最终调用的都是doRegisterBean()方法 , 都是会把传入的类转换为一个BeanDefintion

XmlBeanDefinitionReader

既然有解析类的读取器的 , 那么也就应该有解析xml标签的 , 它就是XmlBeanDefinitionReader , 如下
首先定义一个xml文件

<beans xmlns="http://www.springframework.org/schema/beans"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:context="http://www.springframework.org/schema/context"   xmlns:aop="http://www.springframework.org/schema/aop"   xsi:schemaLocation="http://www.springframework.org/schema/beans   https://www.springframework.org/schema/beans/spring-beans.xsd   http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"   ><bean id="member" class="com.lyh.service.MemberService"/></beans>

然后我们通过如下的方式来获取

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext); xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");MemberService memberService = (MemberService) applicationContext.getBean("memberService");memberService.test();}}

ClassPathBeanDefinitionScanner

前面介绍的两个是读取器 , 现在来介绍一个BeanDefinition扫描器 , 读取器 , 读取类以及xml文件然后解析成为一个BeanDefintion , 那么扫描器, 那么就是读取某个包路径下的类 , 然后进行解析 ,比如,扫描到的类上如果存在@Component 注解,那么就会把这个类解析为一个BeanDefinition , 如下

申明一个ScannerService来测试

public class ScannerService {public void test(){System.out.println("执行了ScannerService.test()方法");}}

取消AppConfig.class这个入参

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");scannerService.test();}}

这样运行肯定是报错的 , 即使在ScannerService类加上了@Component注解 , 因为这里没有传配置文件进去 , 所以构造的是一个空的Spring容器
报错信息如下:

Exception in thread “main” java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@433c675d has not been refreshed yet

在这里插入代码片

它提示我们这个容器还没有刷新一下 , 加一行代码来刷新一下

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.refresh();ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");scannerService.test();}}

发现刷新之后还是报错 , 报错信息如下 :

Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘scannerService’ available
没有一个名为scannerService的Bean用来使用

我们现在用这个扫描器试一下

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);scanner.scan("com.lyh");ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");scannerService.test();}}

发现控制台打印了 “执行了ScannerService.test()方法” , 也就是说这个扫描器生效了 , 它扫描到了ScannerService并且这个类加了@Component , 就表示这个类需要注册为一个Bean , 就会把这个类解析并放入Spring容器 , 其实比较细心的话就可以发现ClassPathBeanDefinitionScanner这个类是在之前申明AnnotatedBeanDefinitionReader读取器的时候也申明了

public AnnotationConfigApplicationContext() {StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");// 额外会创建StandardEnvironmentthis.reader = new AnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner = new ClassPathBeanDefinitionScanner(this);}

所以这里我们就知道了 , 我们的Spring容器它既可以去注册某一个类成为Bean ,也可以去扫描 , 当然它的内部会进行扫描 , 我们自己触发也是可以的 , 所以AnnotationConfigApplicationContext 也是有这两个功能的 , 一个是直接注册 , 一个是扫描

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 需要传入一个包路径applicationContext.scan();

BeanDefinition子类

上面我们说到 , BeanDefinition是一个接口 , 那么重要的实现类有这么三个 :
1.GenericBeanDefinition
2.AnnotatedGenericBeanDefinition
3.ScannedGenericBeanDefinition

它们之前的父子关系是这样的

AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition的区别

先来看ScannedGenericBeanDefinition , 它表示是扫描出来的BeanDefinition的类型
我们来看源码 , 从刚刚scan()的源码进去

scanner.scan(“com.lyh”);

public int scan(String... basePackages) {int beanCountAtScanStart = this.registry.getBeanDefinitionCount();doScan(basePackages);// Register annotation config processors, if necessary.if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);}

再来看doScan()

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 解析@Lazy、@Primary、@DependsOn、@Role、@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查Spring容器中是否已经存在该beanNameif (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}

再来看findCandidateComponents()

public Set<BeanDefinition> findCandidateComponents(String basePackage) {if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {return scanCandidateComponents(basePackage);}}

再来看scanCandidateComponents()

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {// 获取basePackage下所有的文件资源String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// excludeFilters、includeFilters判断if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setSource(resource);if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}else {if (traceEnabled) {logger.trace("Ignored because not matching any filter: " + resource);}}}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);}}else {if (traceEnabled) {logger.trace("Ignored because not readable: " + resource);}}}}catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);}return candidates;}

我们可以看到这样一行代码 :
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
就表示扫描出来的BeanDefinition类型是ScannedGenericBeanDefinition

再来看AnnotatedGenericBeanDefinition
我们还是进入到AnnotationConfigApplicationContext的构造方法

public AnnotationConfigApplicationContext(Class<" />

ChildBeanDefinition和RootBeanDefinition的区别

ChildBeanDefinition基本从Spring2.5开始就很少用了 , 都是用GenericBeanDefinition来代替
RootBeanDefinition 它是常用的 , 而且用的比较多 , 因为RootBeanDefinition和Bean的生命周期有关 , 所以我们后面来讲 , 它是和合并beanDefinition有关的 , 目前为止有这个合并beanDefinition的概念即可

BeanFactory

BeanFactory它是一个接口 , 表示Bean工厂 , 它的作用就是用来创建Bean对象的 , 我们一般常用的Bean工厂是ApplicationContext , 为什么说ApplicationContext 也是Bean工厂呢?
源码中它的类是这样定义的

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

而ListableBeanFactory, HierarchicalBeanFactory都继承了BeanFactory , 所以说ApplicationContext它其实就是一个Bean工厂 , 所以ApplicationContext 他肯定拥有BeanDactory的功能 , 那么ApplicationContext和BeanFactory有什么区别呢?

其实从源码我们不难看出 , 它还继承了一些其他的接口, 比如ApplicationEventPublisher事件发布器 ,
EnvironmentCapable获取环境变量等 , 这个是BeanFactory所没有的 ,它的功能也就比BeanFactory更强大一点

DefaultListableBeanFactory

上面说到解析为BeanDefintion之后会注册到Spring容器中 , 那么什么是容器? 其实在DefaultListableBeanFactory这个类中就有体现 , 源码中是这样定义的

/** Map of bean definition objects, keyed by bean name. */private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

其实说白了它就是一个map , key就是Bean的名称 , value就是解析出来的Map ,当然 , 我们也可以把Spring容器理解为单例池 , 单例池就是一个Map , 它存的就是所有的单例Bean , key也是Bean的名称 , value是Bean的实例 , 源码是这样定义的

// 单例池private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

是在我们在使用AnnotationConfigApplicationContext的时候就有用到这个类 , 我们需要知道的是 , 在加载构造方法之前 , 它会先加载父类的构造方法 , 而在父类的构造方法中就初始化一个DefaultListableBeanFactory , 其实我们的getBean()功能就是DefaultListableBeanFactory 实现的

public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory();}

DefaultListableBeanFactory的功能是非常强大的 , 支持很多功能,可以通过查看DefaultListableBeanFactory的类继承实现结构来看

Aliasregistry

Aliasregistry ,通过类图我们可以看到DefaultListableBeanFactory也是实现了Aliasregistry接口的 ,
而Aliasregistry接口提供的就是别名注册的功能 , 如果没有实现这个接口 , 就表示一个Bean只能有一个名称 ,但是实现了这个接口 , 我们就可以给这个Bean起一个别名

singletionBeanisgtry

singletionBeanisgtry , 它提供的就是单例Bean的功能

BeanDinfinitionRegistry

BeanDinfinitionRegistry , 实现了这个接口就可以有BeanDinfinition注册的功能

HierarchicalBeanFactory

HierarchicalBeanFactory , 它可以获取父Bean工厂 , 如果实现了这个接口 , 就表示这个Bean工厂是支持父子Bean工厂的 , 也就是说如果有两个Bean工厂 , 它们是父子Bean工厂 , 如果子Bean工厂get不到Bean , 那么我们就会从父工厂去get

ListableBeanFactory

ListableBeanFactory , 它可以根据Bean的名称判断是否包含BeanDefinition , 以及获取BeanDefinition的数量 , 获取所有BeanDefinition的名称也就是Bean的名称 , 比如还可以根据指定类型获取Bean的名称 , 其实这个类提供的也就是一个展示的功能 , Bean的名称 , 数量…等

AutowireCapableBeanFactory

AutowireCapableBeanFactor,是直接继承了BeanFactory,在BeanFactory的基础上,支持 在创建Bean的过程中能对Bean进行自动装配

ConfigurableBeanFactory

在HierarchicalBeanFactory和SingletonBeanRegistry的基础上, 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置 Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示 该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持 Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能

AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactor, 继承了AbstractBeanFactory,实现了 AutowireCapableBeanFactory,拥有了自动装配的功能

对于这些接口 , 类不明白也没关系, 着重理解BeanFactory就行 , 其实这也可以充分的体会到Spring内部这种面向接口的思想 , 在以后的工作中 ,我们也可以模仿Spring这种面向接口的设计思想 , 每一个接口都是一个功能 , 如果想拥有这个功能 , 那我们实现这个接口就行

ApplicationContext

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

HierarchicalBeanFactory

拥有获取父BeanFactory的功能

ListableBeanFactory

拥有获取beanNames的功能

ResourcePatternResolver

资源加载器,可以一次性获取多个资源(文件资源等等)

public class TestSpring {public static void main(String[] args) throws IOException {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);Resource resource = applicationContext.getResource("file://E:\\studywork\\spring-framework-5.3.10\\spring-lyh\\src\\main\\java\\com\\lyh\\service\\UserService.java");System.out.println(resource.contentLength());System.out.println(resource.getFilename());Resource resource1 = applicationContext.getResource("https://www.baidu.com");System.out.println(resource1.contentLength());System.out.println(resource1.getURL());Resource resource2 = applicationContext.getResource("classpath:spring.xml");System.out.println(resource2.contentLength());System.out.println(resource2.getURL());String message = applicationContext.getMessage("test", null, new Locale("en"));System.out.println("message : " + message);}}

还可以一次性获取多个

Resource[] resources = applicationContext.getResources("classpath:com/lyh/*.class");for (Resource re : resources) {System.out.println(re.contentLength());System.out.println(re.getFilename());}

源码中是在扫描的时候用到的 , 这一块的源码之前有详细的入口 , 不清楚的可以在本篇文章中Ctrl+f搜一下这个方法 , 这个方法就会传入一个包路径 , 然后加载资源

在开发中我们可以这样使用

@Componentpublic class MemberService implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void test1(){Resource resource = applicationContext.getResource("");System.out.println("test1方法被调用 resource " + resource);}}

EnvironmentCapable

可以获取运行时环境(没有设置运行时环境功能)

public class TestSpring {public static void main(String[] args){AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 获取操作系统层面的环境变量Map<String, Object> systemEnvironment = applicationContext.getEnvironment().getSystemEnvironment();System.out.println(systemEnvironment);System.out.println("=======");// 获取通过-d的方式指定的配置文件Map<String, Object> systemProperties = applicationContext.getEnvironment().getSystemProperties();System.out.println(systemProperties);System.out.println("=======");// 获取通过注解指定的配置文件的值 : @PropertySource("classpath:spring.properties")MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();System.out.println(propertySources);System.out.println("=======");// 也可以指定具体的值 操作系统System.out.println(applicationContext.getEnvironment().getProperty("NO_PROXY"));// 通过-d指定的参数System.out.println(applicationContext.getEnvironment().getProperty("sun.jnu.encoding"));// 获取spring.properties配置文件的内容System.out.println(applicationContext.getEnvironment().getProperty("lyh"));}}

ApplicationEventPublisher

拥有广播事件的功能(没有添加事件监听器的功能)
首先在Appconfig定义一个事件发布器

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

在工作中我们也可以这样用

@Componentpublic class MemberService implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void test(){String message = applicationContext.getMessage("test", null, new Locale("en"));System.out.println("test方法被调用 message为 " + message);}public void test1(){Resource resource = applicationContext.getResource("");System.out.println("test1方法被调用 resource " + resource);}public void test2(){applicationContext.publishEvent("kkk");System.out.println("test2方法被调用 发布了事件");}}

当我们调用test2()方法时就会发布一个事件

MessageSource

拥有国际化功能
我们首先在resources下新建一个文件
右键resources --> new --> resource Bundle , 然后就会出来如下图所示的界面 , 我们首先定义一个名称 : message(名称随意) , 然后添加一个英语 , 点击确认

然后就会帮我们创建出两个文件

我们在两个文件中指定如下内容 , 内容随意

在AppConfig中定义一个MessageSource

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

有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。
同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:

public class TestSpring {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// en对应配置文件message_en的'en'String message = applicationContext.getMessage("test", null, new Locale("en"));System.out.println(message);}}

但是我们在实际开发中肯定不是以这样的方式去获取国际化资源 , 那么应该怎么做呢" />

ConfigurableApplicationContext

继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能

AbstractApplicationContext

实现了ConfigurableApplicationContext接口 , AbstractApplicationContext是Spring应用上下文中最重要的一个类,这个抽象类中提供了几乎ApplicationContext的所有操作。主要有容器工厂的处理,事件的发送广播,监听器添加,容器初始化操作refresh方法,然后就是bean的生成获取方法接口等。主要还是提供了一些方法,复杂的操作也是没有太多。

GenericApplicationContext

继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)

AnnotationConfigRegistry

可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描

AnnotationConfigApplicationContext

继承了GenericApplicationContext,实现了AnnotationConfigRegistry

AnnotationConfigRegistry

拥有了以上所有的功能

ClassPathXmlApplicationContext


它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition , 并且现在用AnnotationConfigApplicationContext比较多一点 , 所以ClassPathXmlApplicationContext就不着重说了

PropertyEditor

这其实是JDK中提供的类型转化工具类 , 在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。

定义类型转换器

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<" />
它首先判断当前Bean的类型是否和给定的类型相符 , 如果不同 , 就会进行类型转换 , 能不能转的过来 , 就要看有没有定义上面的这些类型转换器 , 如果可以强转, 那么就返回 , 如果不可以强转, 那么就会报异常, 类型不符 , 如果没有指定 , 就直接返回

OrderComparator

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

public class A implements Ordered {@Overridepublic int getOrder() {return 3;}@Overridepublic String toString() {return this.getClass().getSimpleName();}}
public class B implements Ordered {@Overridepublic int getOrder() {return 2;}@Overridepublic String toString() {return this.getClass().getSimpleName();}}
public class Main {public static void main(String[] args) {A a = new A(); // order=3B b = new B(); // order=2OrderComparator comparator = new OrderComparator();System.out.println(comparator.compare(a, b));  // 1List list = new ArrayList<>();list.add(a);list.add(b);// 按order值升序排序list.sort(comparator);System.out.println(list);  // B,A}}

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

@Order(3)public class A {@Overridepublic String toString() {return this.getClass().getSimpleName();}}
@Order(2)public class B {@Overridepublic String toString() {return this.getClass().getSimpleName();}}
public class Main {public static void main(String[] args) {A a = new A(); // order=3B b = new B(); // order=2AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();System.out.println(comparator.compare(a, b)); // 1List list = new ArrayList<>();list.add(a);list.add(b);// 按order值升序排序list.sort(comparator);System.out.println(list); // B,A}}

BeanPostProcessor

BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,比如通过一下代码定义一个BeanPostProcessor:

@Componentpublic 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; }}

一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。

我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。

BeanFactoryPostProcessor

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。比如,我们可以这样定义一个BeanFactoryPostProcessor:

@Componentpublic class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {  System.out.println("加工beanFactory"); }}

我们可以在postProcessBeanFactory()方法中对BeanFactory进行加工。

FactoryBean

上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean:

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

通过上面这段代码,我们自己创造了一个UserService对象,并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。

有同学可能会想到,通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?

其实在很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。而FactoryBean只是经过了初始化后这一步 , 因为虽然是以实现FactoryBean重写方法的方式定义的Bean , 但是不能把AOP这个功能给抛弃了

​它的源码也是在doGetBean() , 如下图 , 一定要注意transformedBeanName()这个方法 , 等等我们来讲用途

它会判断 , 如果没有实现FactoryBean ,会直接返回 , 否则进行处理


到这里 , 它就会执行getObject()方法 , 然后返回 , getObject()方法也就是你自己实现了FactoryBean接口所重写的方法

然后我们再来说第一张图片的transformedBeanName()方法 , 如果实现了FactoryBean , 那么这个类也是一个Bean ,那么我们想获取这个Bean怎么获取呢?就比如上面的例子 , 我想获取LyhFactoryBean , 怎么获取呢?

public class TestSpring {public static void main(String[] args){AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 返回getObject()方法返回的BeanUserService userService = (UserService)applicationContext.getBean("lyhFactoryBean");System.out.println(userService);// 返回LyhFactoryBeanLyhFactoryBean lyhFactoryBean = (LyhFactoryBean)applicationContext.getBean("&lyhFactoryBean");System.out.println(lyhFactoryBean);

所以transformedBeanName()方法其实是针对这种情况做了处理

ExcludeFilter和IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器。

比如以下配置,表示扫描com.lyh这个包下面的所有类,但是排除UserService类,也就是就算它上面有
@Component注解也不会成为Bean。

@ComponentScan(value = "com.lyh",  excludeFilters = {@ComponentScan.Filter(             type = FilterType.ASSIGNABLE_TYPE,              classes = UserService.class)}.)public class AppConfig {}

再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。

@ComponentScan(value = "com.lyh",  includeFilters = {@ComponentScan.Filter(             type = FilterType.ASSIGNABLE_TYPE,              classes = UserService.class)})public class AppConfig {}

FilterType分为:

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

在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下Spring扫描过程中会认为类上有@Component注解的就是Bean。

MetadataReader、ClassMetadata、AnnotationMetadata

在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。

MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:

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

那么有人会想 , 为什么不用反射呢?
其实SimpleMetadataReaderFactory类的功能是非常强大的 , 它可以获取接口的名称 , 获取内部类的名称 , 通过一个方法的直接调用就可以 , 但是用反射获取要写不少代码 , 对于这些类的API大家可以动手来试验一下 , 更容易理解

需要注意的是SimpleMetadataReader去解析类时,使用的ASM技术。

为什么要使用ASM技术

Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。

本篇文章到这里就结束了 , 介绍了Spring一些比较重要的常用的类的基本功能 , 概念, 在阅读Spring的源码中 , 我们可以知道个所以然 , 知道大概是干什么用的 , 这样会比较方便一点