本篇文章将对Spring底层的一些概念做一些简单的分析 , 也是为了方便后续在阅读源码的时候更加的方便
BeanDefintion
BeanDefintion是一个接口 , 它表示一个Bean的定义 , BeanDefintion存在很多属性来描述一个Bean的特点 , Spring在扫描完需要注册的Bean之后会进行解析 , 而解析的数据就会存入到BeanDefintion
我们在定义Bean的时候可以分为两种方式 :
申明式
申明式定义一个Bean就比如我们用的@Bean , @Component等注解 , 或者是xml标签的形式来定义一个Bean
编程式
编程式就是通过写代码的方式来定义 , 如下
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注解的结果为ScopeMetadata ScopeMetadata 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、@Description static 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、ClassPathBeanDefinitionScanner this(); // 注册bean配置类 register(componentClasses); // 刷新上下文 refresh(); }
然后看this()方法
public AnnotationConfigApplicationContext() { StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); // 额外会创建StandardEnvironment this.reader = new AnnotatedBeanDefinitionReader(this); createAnnotatedBeanDefReader.end(); this.scanner = new ClassPathBeanDefinitionScanner(this);
我们就可以看到它构造了一个AnnotatedBeanDefinitionReader对象 , 其实Spring容器本身也有register()方法
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); applicationContext.register();
其实它们使用的是同一个方法 , 看一看applicationContext.register()方法的源码
@Override public 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文件
<?xml version="1.0" encoding="UTF-8"?> <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"); // 额外会创建StandardEnvironment this.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 doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { Set 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、@Description AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 检查Spring容器中是否已经存在该beanName if (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 findCandidateComponents(String basePackage) { if (this.componentsIndex != null && indexSupportsIncludeFilters()) { return addCandidateComponentsFromIndex(this.componentsIndex, basePackage); } else { return scanCandidateComponents(basePackage); } }
再来看scanCandidateComponents()
private Set scanCandidateComponents(String basePackage) { Set 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... componentClasses) { // 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner this(); // 注册bean配置类 register(componentClasses); // 刷新上下文 refresh(); }
看register()方法
@Override public 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(); }
再看 this.reader.register();
public void register(Class... componentClasses) { for (Class componentClass : componentClasses) { registerBean(componentClass); } }
再看registerBean()
public void registerBean(Class beanClass) { doRegisterBean(beanClass, null, null, null, null); }
再看doRegisterBean()
private void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class[] qualifiers, @Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[] customizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(supplier); // 解析@Scope注解的结果为ScopeMetadata ScopeMetadata 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 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); }
我们可以看到这样一行代码 :
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
就表示扫描并解析到的BeanDefinition类型是AnnotatedGenericBeanDefinition类型
我们简单理解 , 一个扫描器 ,一个读取器 , 最终得到的都是一个BeanDefinition对象 , 但是他是进行区分的
当然还有比较重要的两个BeanDefinition子类
1.RootBeanDefinition
2.ChildBeanDefinition
他们的父子关系是这样的
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 beanDefinitionMap = new ConcurrentHashMap<>(256);
其实说白了它就是一个map , key就是Bean的名称 , value就是解析出来的Map ,当然 , 我们也可以把Spring容器理解为单例池 , 单例池就是一个Map , 它存的就是所有的单例Bean , key也是Bean的名称 , value是Bean的实例 , 源码是这样定义的
// 单例池 private final Map 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搜一下这个方法 , 这个方法就会传入一个包路径 , 然后加载资源
在开发中我们可以这样使用
@Component public class MemberService implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public 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 systemEnvironment = applicationContext.getEnvironment().getSystemEnvironment(); System.out.println(systemEnvironment); System.out.println("======="); // 获取通过-d的方式指定的配置文件 Map 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定义一个事件发布器
@Bean public ApplicationListener applicationListener() { return new ApplicationListener() { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("接收到了一个事件 : " + event); } }; }
在工作中我们也可以这样用
@Component public class MemberService implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public 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
@Bean public 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); } }
但是我们在实际开发中肯定不是以这样的方式去获取国际化资源 , 那么应该怎么做呢?
@Component public class MemberService implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public 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); }
就像这样 , 我们实现一下ApplicationContextAware接口 , 这样不就想怎么用就怎么用了吗
关于ApplicationContext我们也有两个经常使用的具体的实现类
AnnotationConfigApplicationContext
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:
@Bean public CustomEditorConfigurer customEditorConfigurer() { CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer(); Map, Class> propertyEditorMap = new HashMap<>(); // 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化 propertyEditorMap.put(User.class, StringToUserPropertyEditor.class); customEditorConfigurer.setCustomEditors(propertyEditorMap); return customEditorConfigurer; }
假设现在有如下Bean:
@Component public class UserService { @Value("lyh") private User user; public void test() { System.out.println(user); } }
当我们使用/@Value(“lyh”)想为user赋值时 , Spring就会去看程序员有没有定义一个类型转换器 , 可以把String转换为user, 因为我们刚刚向容器注册了一个类型转换器, 那么user属性就能正常的完成属性赋值
ConversionService Spring中提供的类型转化服务,它比PropertyEditor更强大 public class StringToUserConverter implements ConditionalGenericConverter { @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { // sourceType.getType() : 带转换的类型 // targetType.getType(): 转换后类型 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; } }
public class TestSpring { public static void main(String[] args){ DefaultConversionService conversionService = new DefaultConversionService(); conversionService.addConverter(new StringToUserConverter()); User value = conversionService.convert("1", User.class); System.out.println(value); } }
如何向Spring中注册ConversionService:
@Bean public ConversionServiceFactoryBean conversionService() { ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean(); conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter())); return conversionServiceFactoryBean; }
TypeConverter
整合了PropertyEditor和ConversionService的功能,是Spring内部用的 , 因为我们在实际使用的时候可能会同时定义PropertyEditor和ConversionService , 所以Spring就用SimpleTypeConverter来把两种方式都添加进去
public class TestSpring { public static void main(String[] args){ SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor()); //typeConverter.setConversionService(conversionService); User value = typeConverter.convertIfNecessary("1", User.class); System.out.println(value); }
这个类型转换器在源码中是这样体现的
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); MemberService memberService = applicationContext.getBean("memberService" , MemberService.class); System.out.println(memberService);
这样我们就不用强制转换了 , 我们来看看源码 , 我们进入到doGetBean()方法
@Override public T getBean(String name, Class requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, requiredType); }
继续进入getBean() , 此时应该到了BeanFactory的getBean();
T getBean(String name, Class requiredType) throws BeansException;
然后进入到AbstractBeanFactory的getBean();
@Override public T getBean(String name, Class requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); }
进入到doGetBean()即可
最后会看到
return adaptBeanInstance(name, beanInstance, requiredType);
它首先判断当前Bean的类型是否和给定的类型相符 , 如果不同 , 就会进行类型转换 , 能不能转的过来 , 就要看有没有定义上面的这些类型转换器 , 如果可以强转, 那么就返回 , 如果不可以强转, 那么就会报异常, 类型不符 , 如果没有指定 , 就直接返回
OrderComparator
OrderComparator是Spring所提供的一种比较器,可以用来根据@Order注解或实现Ordered接口来执行值进行笔记,从而可以进行排序 , 比如:
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 } }
另外,Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。比如:
@Order(3) public class A { @Override public String toString() { return this.getClass().getSimpleName(); } }
@Order(2) public class B { @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 AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator(); 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 } }
BeanPostProcessor
BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,比如通过一下代码定义一个BeanPostProcessor:
@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; } }
一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。
我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。
BeanFactoryPostProcessor
BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。比如,我们可以这样定义一个BeanFactoryPostProcessor:
@Component public class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("加工beanFactory"); } }
我们可以在postProcessBeanFactory()方法中对BeanFactory进行加工。
FactoryBean
上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean:
@Component public 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()方法返回的Bean UserService userService = (UserService)applicationContext.getBean("lyhFactoryBean"); System.out.println(userService); // 返回LyhFactoryBean LyhFactoryBean 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的源码中 , 我们可以知道个所以然 , 知道大概是干什么用的 , 这样会比较方便一点