目录
一,包扫描方式
第二种方式 包扫描方式(第一种是直接给一个bean的class对象,通过扫描类进行注解。)现在是给出MainConfig类的包,该包下面可能有几个配置类,入口:构造方法。
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
包扫描方式,如果让我实现,无非就是在第一种方式的基础上,增加了自己找到bean的过程,我们需要拿到路径,
扫描指定包路径及其子包下的注解类,为了使新添加的类被处理,必须手动调用refresh()方法刷新容器。
public void scan(String... basePackages) {
this.scanner.scan(basePackages);
}
可以看到,我们的scanner 包扫描类排上用场了。ClassPathBeanDefinitionScanner类
//调用类路径Bean 定义扫描器入口方法。
public int scan(String... basePackages) {
//获取容器 中已经 注册的bean的个数。
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//启动扫描器 扫描 给定包。 ---【深入】----
doScan(basePackages);
//注册注解配置 (Annotation config )处理器。
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//返回注册的bean的个数。
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
这里也是一个入口,真正开始扫描的当然是doScan()这里方法,而ClassPathBeanDefinitionScanner这个类,也可以整体进行一下研究,意义还是大。(这里为什么要获取已经注册的bean,或许是为了在扫描的时候,避免重复加载吧)
doSan()方法:这里或许就如同doRegister()一样,哈哈哈。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
//结果容器准备好
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) { //开始遍历 包路径,一般就是一个
Set<BeanDefinition> candidates = findCandidateComponents(basePackage); //找到符合条件的bean定义
//遍历扫描到的bean
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) { //抽象bean
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) { //注解bean
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) { //封装bean
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder); //保存
registerBeanDefinition(definitionHolder, this.registry); //注册Bean
}
}
}
return beanDefinitions;
}
分析一下:
1.创建存放 封装bean 的集合:Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
2.扫描路径,获得beanDefinition:Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
3.遍历扫描到的beanDefinition:这里就如同doRegister对bean坐的操作一样。所以我们重点放在第二部,解析路径。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
这里判断了个什么鬼,表示看不懂,反正走add...()方法
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
//创建扫描到的类集合
Set<BeanDefinition> candidates = new LinkedHashSet<>();
Set<String> types = new HashSet<>();
for (TypeFilter filter : this.includeFilters) {
String stereotype = extractStereotype(filter);
types.addAll(index.getCandidateTypes(basePackage, stereotype));
for (String type : types) {
//为指定资源获取 元数据 读取器,元数据读取器 通过汇编(ASM) 读取资源的元信息。
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
//如果扫描到的类符合 容器配置的过滤规则。
if (isCandidateComponent(metadataReader)) { //--这里【深入】一下
//通过汇编(ASM) 读取资源字节码中的bean定义的元信息。
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
。。。。。
return candidates;
}
(注意)这里有一个概念,也是bean生命周期中的,TypeFilter,bean的过滤器,他可以设置哪些bean需要注册(为什么需要这个,比如说,不同的环境,开发,测试,生成,会使用不同的配置,不同的bean,不同的操作系统,不同的浏览器,根据环境而定,所以这里需要进行拦截,在一些环境下,有些bean是不需要启动的,还比如说,多个扫描,第一次扫描不用启动Controller,让mvc的扫描器去启动Controller,这些都需要进行拦截。并且可以自定义拦截器。
这里就是通过元数据,然后返回了sbd这个封装的bean,直接把这个bean存进了集合里面,
细节观看:
1.basePackage如何转换的: 通过路径,返回了type。这里说了是一个String集合。(大胆猜测,这里应该是拿的每一个类的路径,但是为什么取名字叫type)
public Set<String> getCandidateTypes(String basePackage, String stereotype) {
List<Entry> candidates = this.index.get(stereotype);
if (candidates != null) {
return candidates.parallelStream()
.filter(t -> t.match(basePackage))
.map(t -> t.type)
.collect(Collectors.toSet());
}
return Collections.emptySet();
}
2.通过这个字符串,生成了元素据MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
看见这个参数名字没有 className 上一步的type没有猜错吧。。
public MetadataReader getMetadataReader(String className) throws IOException {
try {
//className是 .xx.xx的形式,这里要转换成为pc file路径形式。
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
//通过路径获得资源。
Resource resource = this.resourceLoader.getResource(resourcePath);
//看来这个方法又是一个入口。
return getMetadataReader(resource);
}
}
//----------------------------
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
这里资源装载器又排上了用场,这里找到的应该是一个class文件吧。。通过resource 返回了一个类,这个类应该是封装了resource才对。
final class SimpleMetadataReader implements MetadataReader {
private final Resource resource; //在这里。
private final ClassMetadata classMetadata; //元数据出现了
private final AnnotationMetadata annotationMetadata; //还有注解的元数据,
}
到了这里,应该说就和 直接register(class)一样了吧,什么数据都准备好了。
回到ClassPathBeanDefinitionScanner类中,遍历beanDefinition,将其封装成为。。。Holder,进行register()后面的就是老套路了。
二,refresh()
不管是直接给出配置类,还是给出扫描路径,最后都会走refresh()方法,它和xml方式都一样,还是refresh()方法,但是AbstractApplicationContext类使用委派模式,注解模式和xml模式实现的方法是不同的,现在我们看源码分析:
2.2 obtainFreshBeanFactory()
注解方式实现的此步骤比较简单,直接从GenericApplicationContext中获取beanFactory并返回。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//第二层类
refreshBeanFactory();
//返回DefaultListableBeanFactory 也由第二层实现,获得上 方法初始化的结果。
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
return beanFactory;
}
refreshBeanFactory()方法就是第二层子类的方法,在annotation中,它只有两个父类,这里显示第二层,那么就是GenericApplicationContext类:
protected final void refreshBeanFactory() throws IllegalStateException {
this.beanFactory.setSerializationId(getId());
}
设置了序列化id,其他就没有了,没有xml方式的创建DefaultBeanFactory的过程,因为GenericApplicationContext在无参构造方法中就已经初始化了beanFactory,并且还注入了默认的6个bean和我们自定义的配置bean。
2.3 prepareBeanFactory()
该方法, 在后面的refresh()章节中还会讲过,是xml方式的,这个方法是通用的,重点是注册了两个后置处理器:ApplicationContextAwareProcessor处理器和ApplicationListenerDetector处理器
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks. 添加后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //第一个后置处理器
//忽略的接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
.....
//依赖对象的设置
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); //第二个后置处理器
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans. 注册默认 环境 bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
效果:
2.4 postProcessBeanFactory()
在spring基于注解启动或者xml初始化的时候,这个方法是空的,未实现。
而使用springboot启动,会调用AnnotationConfigServletWebServerApplicationContext的方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 调用弗雷的后置处理工厂bean
super.postProcessBeanFactory(beanFactory);
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
// 注册作用域
registerWebApplicationScopes();
}
给beanFactory注册一个后置处理器之后,会调用registerWebApplicationScopes(),注册作用范围:
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) {
// request
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
// session
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
// application
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
// 注册解析依赖
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
2.5 invokeBeanFactoryPostProcessors()
(重点)调用后置处理器 ,首先调用PostProcessorRegistrationDelegate后置处理器注册代理类,它是一个独立的类,没有继承关系。
invoke---调用
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//【入】,使用后置处理器
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
// 获取后置处理器列表
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
重点是第一个方法,调用后置处理器的时候,开始进行bean的解析。!
注意,beanFactoryPostProcessors字段还是空的,因为这里调用的是AbstractApplicationContext容器的属性字段,在上一步注册的beanPostProcessors是BeanFactory的属性字段。
跳转到代理类:PostProcessorRegisterationDelegate类中,该类中的代码方法很长,我们看核心部分:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//定义两个处理器集合,两个类型其实是继承关系 regular---常规的
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//执行 扩展的BeanFactoryPostProcessor, 因为可以 自定义扩展(用户自定义的后置处理器,实现BeanDefinitionRegistryPostProcessor接口)
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
.... 因为没有自定义,所有省略了
}
//存放后置处理器 列表
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
【重点】 此处获得了 后置处理器名字 从beanFactory中
String[] postProcessorNames = // 获取 下面这个类型的 bean,然后进行排序
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//获得实例 ,并保存
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
【重点】
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear(); //清0,下一段不重复使用
分开步骤分析:
1.找到后置处理器:
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
可见这个接口,只有唯一实现类,所以非他莫属
具体的实现在DefaultListableBeanFactory类中,也就是容器(现在容器中存放了几个初始的beanDefinition)中进行查找:
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) { //不正常情况
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type); //缓存中直接获取
if (resolvedBeanNames != null) {
return resolvedBeanNames;
} //缓存未命中
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
返回结果:
内部处理Configuration注解的处理器
然后会使用beanFactory.getBean()获取该bean的实例,这个时候由于里面的依赖,所以会实例化很多个bean。
2.执行后置处理器方法
invokeBeanDefinitionRegistryPostProcessors()
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry); //执行 重点ConfigurationClassPostProcessor类
}
}
传入的自然就是ConfigurationClassPostProcessor类,进行后置处理,调用的是处理器的方法,
具体解析:请看下一节的讲解!