Spring Framework

1.Spring 5下载

1.进入Spring官网

2.进入Spring Framework

3.进入Spring5的github 按照下面步骤

然后根据地址下载需要的版本

Spring的在线文档

离线文档:

2.Spring学习的核心内容:

1.Spring核心学习内容IOC,AOP,jdbcTemplate,声明式事务

2.IOC:控制反转,可以管理java对象

3.AOP:切面编程

4.JDBCTemplate:是spring提供一套访问数据库的技术,应用性强,相对好理解

5.声明式事务:基于IOC/AOP实现事务管理,理解需要花时间

6.IOC.AOP是重点同时也是难点

Spring几个重要概念:

1.Spring可以整合其他的框架(Spring是管理框架的框架)

2.Spring有两个核心的概念:IOC和AOP

3.传统的开发模式:

程序------>环境//程序读取环境配置,然后自己创建对象

IOC的开发模式:容器--------->程序//容器创建好对象,程序直接使用

1.Spring根据配置文件xml/注解,创建对象,并放入到容器(ConcurrentHashMap)中,并且可以完成对象之间的依赖。

2.当需要使用某个对象实例的时候,就直接从容器中获取即可。

3.程序员可以更加关注如何使用对象完成相应的业务。

4.DI依赖注入,可以理解成事IOC的另外叫法。

5.Spring最大的价值,通过配置,给程序提供需要使用的web层对象,这个是核心价值所在,也是IOC的具体体现,实现解耦。


3.手写简易SpringFrame框架:

实现一下内容:

1.手写模拟Spring容器启动过程底层实现

2.手写模拟Spring解析配置类底层实现

3.手写模拟Spring扫描Bean过程底层实现

4.手写模拟Bean生命周期创建过程底层实现

5.手写模拟Bean生命周期依赖注入过程底层实现

6.手写模拟Bean生命周期Aware回调过程底层实现

7.手写模拟Bean生命周期初始化过程底层实现

8.手写模拟BeanDefinition生成过程底层实现

9.手写模拟@Component,@ComponentScan

10.手写模拟@Autowired,@PostConstruct

11.手写模拟BeanPostProcessor后置处理底层实现

12.手写模拟Spring AOP过程底层实现

13.手写模拟Pointcut,Advisor,Advice底层实现


代码仓库:https://gitee.com/CHEN--YUQIAO/spring-frame 参考学习


4.Spring源码中核心组件的使用与解析

4.1BeanDefinition

BeanDefinition是非常非常核心的一个概念,一个BeanDefinition表示一个Bean定义,Spring会根据BeanDefinition来创建具体的Bean对象。

BeanDefinition中常用的属性:

  • beanClass,表示Bean的类型
  • scope,表示Bean的作用域,比如单例或多例
  • LazyInit:表示Bean是不是懒加载的
  • initMethodName:表示Bean初始化时要执行的方法
  • destoryMethodName:表示Bean销毁时要执行的方法

当使用@Bean,@Component等方式定义Bean时,Spring底层就会解析这些标签和注解生成对应的BeanDefinition对象。(声明式创建)

也可以通过编程式定义和注册BeanDefinition:

java 复制代码
      AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(DeviceService.class);

        BeanDefinition definition=new AnnotatedGenericBeanDefinition(DeviceService.class);
        definition.setScope("prototype");
        definition.setLazyInit(false);
        definition.setInitMethodName("a");
        
        applicationContext.registerBeanDefinition("deviceService",definition);

5.BeanDefinition扫描过程源码解析

java 复制代码
package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.type.filter.TypeFilter;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {


	@AliasFor("value")
	String[] basePackages() default {};

	@AliasFor("value")
	String[] basePackages() default {};

Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	Class<?>[] basePackageClasses() default {};

	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

	
	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

	
	boolean useDefaultFilters() default true;

	
	Filter[] includeFilters() default {};

	
	Filter[] excludeFilters() default {};

	
	boolean lazyInit() default false;



	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {

	
		FilterType type() default FilterType.ANNOTATION;

	
		@AliasFor("classes")
		Class<?>[] value() default {};

		
		 
		@AliasFor("value")
		Class<?>[] classes() default {};

		
		String[] pattern() default {};

	}

}
java 复制代码
/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.annotation;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * Parser for the @{@link ComponentScan} annotation.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @since 3.1
 * @see ClassPathBeanDefinitionScanner#scan(String...)
 * @see ComponentScanBeanDefinitionParser
 */
class ComponentScanAnnotationParser {

	private final Environment environment;

	private final ResourceLoader resourceLoader;

	private final BeanNameGenerator beanNameGenerator;

	private final BeanDefinitionRegistry registry;


	public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader,
			BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {

		this.environment = environment;
		this.resourceLoader = resourceLoader;
		this.beanNameGenerator = beanNameGenerator;
		this.registry = registry;
	}


	public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {
		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

		Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
		boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
		scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
				BeanUtils.instantiateClass(generatorClass));

		ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
		if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
			scanner.setScopedProxyMode(scopedProxyMode);
		}
		else {
			Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
			scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
		}

		scanner.setResourcePattern(componentScan.getString("resourcePattern"));

		for (AnnotationAttributes includeFilterAttributes : componentScan.getAnnotationArray("includeFilters")) {
			List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(includeFilterAttributes, this.environment,
					this.resourceLoader, this.registry);
			for (TypeFilter typeFilter : typeFilters) {
				scanner.addIncludeFilter(typeFilter);
			}
		}
		for (AnnotationAttributes excludeFilterAttributes : componentScan.getAnnotationArray("excludeFilters")) {
			List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(excludeFilterAttributes, this.environment,
				this.resourceLoader, this.registry);
			for (TypeFilter typeFilter : typeFilters) {
				scanner.addExcludeFilter(typeFilter);
			}
		}

		boolean lazyInit = componentScan.getBoolean("lazyInit");
		if (lazyInit) {
			scanner.getBeanDefinitionDefaults().setLazyInit(true);
		}

		Set<String> basePackages = new LinkedHashSet<>();
		String[] basePackagesArray = componentScan.getStringArray("basePackages");
		for (String pkg : basePackagesArray) {
			String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
			Collections.addAll(basePackages, tokenized);
		}
		for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(declaringClass));
		}

		scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
				return declaringClass.equals(className);
			}
		});
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}

}
复制代码
ComponentScanAnnotationParser这个类是CompanentScan注解的解析器,用来构建并给scan扫描对象赋值,做扫描前的准备!!
java 复制代码
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) {
//扫描basePackage中的所有类,并注册到BeanDefinitionRegistry中
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
//获取bean的scope
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
//生成beanName
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//给BeanDefinition对象中的属性赋默认值
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
//解析@Lazy,@Primary,@Fallback,@DependsOn,@Role,@Description等注解并赋值给BeanDefinition对应的属性
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
//检查beanName是否已存在
				if (checkCandidate(beanName, candidate)) {
//BeanDefinitionHolder的作用实在BeanDefinition的基础上 添加了beanName
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//如果设置了ScopedProxyMode,则会生成一个新的BeanDefinition,类型为ScopedProxyFactoryBean
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
//注册beanDefinition
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

接下来进入第一个方法,看看是如何实现扫描,获得候选BeanDefinition的:

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

构建扫描路径 → 查找所有类资源 → 读取类元数据 → 双重过滤(规则匹配 + 类合法性) → 生成 Bean 定义

java 复制代码
	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			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);
				}
				try {
//利用ASM技术解析每个.class文件得到类的各种信息(类的元数据信息)
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//利用exludeFileters和includeFilters判断当前class是否为bean
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setSource(resource);
//不能是接口或抽象类,如果是抽象类,但是有@Lookup注解的方法则通过
						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 (FileNotFoundException ex) {
					if (traceEnabled) {
						logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

进入第一重过滤的方法如下:

java 复制代码
	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

第二重过滤方法如下:

此时,对 findCandidateComponents()方法的剖析就已经完成!!

接下来继续看扫描中的

复制代码
checkCandidate()方法 即检查beanName是否已经存在

到这里doscan()方法的逻辑就理清楚了!

接下来,总结一下:扫描的入口------> 容器调用refresh()方法

接着会调用到

复制代码
ConfigurationClassParser类中的
复制代码
 doProcessConfigurationClass()方法

调用parse()回到上面分析过得,创建一个scanner对象,然后再调用doscan()实现扫描!!

相关推荐
我是华为OD~HR~栗栗呀2 小时前
20届-高级开发(华为oD)-Java面经
java·c++·后端·python·华为od·华为
摇滚侠3 小时前
java.lang.RuntimeException: java.lang.OutOfMemoryError
java·开发语言·intellij-idea
sibylyue3 小时前
IDEA cannot resolve method
java·ide·intellij-idea
今天也好累4 小时前
贪心算法之会议安排问题
c++·笔记·学习·算法·贪心算法
翻斗花园刘大胆4 小时前
JavaWeb之快递管理系统(完结)
java·开发语言·前端·jvm·spring·servlet·java-ee
熙客5 小时前
SpringCloudStream:消息驱动组件
java·分布式·spring cloud·rabbitmq
Arenaschi5 小时前
Android
android·linux·运维·笔记·其他·docker
西门吹雪@1325 小时前
springboot项目添加请求链路追踪日志traceId
java·spring boot·后端
新知图书6 小时前
JMeter的定时器
java·jvm·jmeter