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:
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扫描过程源码解析
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 {};}}
/** 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) {@Overrideprotected boolean matchClassName(String className) {return declaringClass.equals(className);}});return scanner.doScan(StringUtils.toStringArray(basePackages));}}
ComponentScanAnnotationParser这个类是CompanentScan注解的解析器,用来构建并给scan扫描对象赋值,做扫描前的准备!!
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的scopeScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName()); //生成beanNameString 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的基础上 添加了beanNameBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); //如果设置了ScopedProxyMode,则会生成一个新的BeanDefinition,类型为ScopedProxyFactoryBeandefinitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder); //注册beanDefinitionregisterBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
接下来进入第一个方法,看看是如何实现扫描,获得候选BeanDefinition的:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {return scanCandidateComponents(basePackage);}}
构建扫描路径 → 查找所有类资源 → 读取类元数据 → 双重过滤(规则匹配 + 类合法性) → 生成 Bean 定义。
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是否为beanif (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;}
进入第一重过滤的方法如下:
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()实现扫描!!