2022-01-21
Spring 注解支持源码流程图
注解实例加载入口
基于注解是: org.springframework.context.annotation.AnnotationConfigApplicationContext
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("org.yang.learnspring");
System.out.println("context 启动成功");
User user = context.getBean(User.class);
System.out.println(user);
创建 BeanFactory
org.springframework.context.annotation.AnnotationConfigApplicationContext.AnnotationConfigApplicationContext(String... basePackages)
public AnnotationConfigApplicationContext(String... basePackages) {
// 见下: 创建了 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner, 这有继承 GenericApplicationContext, 还会调用其构造函数创建了 BeanFactory
this();
//2. 扫描
scan(basePackages);
//3. 刷新 refresh
refresh();
}
//其父 org.springframework.context.support.GenericApplicationContext() 构造方法 创建了 DefaultListableBeanFactory
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
/**
AnnotatedBeanDefinitionReader 是一个读取注解的Bean读取器
**/
this.reader = new AnnotatedBeanDefinitionReader(this);
/**
* BeanDefinition扫描器 用来扫描包或者类, 继而转换为bd
* spring默认的扫描器其实不是这个scanner对象, 而是在后面自己又重新new了一个ClassPathBeanDefinitionScanner
* spring在执行工程后置处理器ConfigurationClassPostProcessor时, 去扫描包时会new一个ClassPathBeanDefinitionScanner
*
* 这里的scanner仅仅是为了程序员可以手动调用AnnotationConfigApplicationContext对象的scan方法
*
*/
this.scanner = new ClassPathBeanDefinitionScanner(this);
//这两个家伙, 参考 https://blog.csdn.net/f641385712/article/details/88059145
}
扫描 scan
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
org.springframework.context.annotation.ClassPathBeanDefinitionScanner.scan(String... basePackages)>
org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(String... basePackages)
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) {
// [2.1. 解析包Components findCandidateComponents] 找到这个包的所有 BeanDefinition
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) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//注册到 BeanFactory [2.20.10.1] ; registry 是创建 Reader时传过来的
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}2.1. 解析包Components findCandidateComponents
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(String basePackage) >
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.scanCandidateComponents(String basePackage)
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//这个包的所有.class文件 //classpath*:org/yang/learnspring/**/*.class
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 [2.1.10 class元数据读取 MetadataReader]
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//过滤?
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
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;
}
2.1.10 class元数据读取 MetadataReader
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.getMetadataReaderFactory()
if (this.metadataReaderFactory == null) {
this.metadataReaderFactory = new CachingMetadataReaderFactory();
}
return this.metadataReaderFactory;
org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(Resource resource)
public MetadataReader getMetadataReader(Resource resource) throws IOException {
if (this.metadataReaderCache instanceof ConcurrentMap) {
// No synchronization necessary...
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
//下
metadataReader = super.getMetadataReader(resource);
//缓存,resource = file [F:\Work\project\learnspring\target\classes\org\yang\learnspring\bean\Book.class]
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
//这个分支读缓存
else if (this.metadataReaderCache != null) {
synchronized (this.metadataReaderCache) {
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
//下
metadataReader = super.getMetadataReader(resource);
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
}
else {
//下
return super.getMetadataReader(resource);
}
}org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(Resource resource)
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(Resource resource)
SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
//很牛逼, 以二进制的方式读取 .class
SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader);
//典型策略模式
//最终使用的是 org.springframework.asm.ClassReader 去读取,
getClassReader(resource).accept(visitor, PARSING_OPTIONS);
this.resource = resource;
this.annotationMetadata = visitor.getMetadata();
}
private static ClassReader getClassReader(Resource resource) throws IOException {
try (InputStream is = new BufferedInputStream(resource.getInputStream())) {
try {
return new ClassReader(is);
}
catch (IllegalArgumentException ex) {
throw new NestedIOException("ASM ClassReader failed to parse class file - " +
"probably due to a new Java class file version that isn't supported yet: " + resource, ex);
}
}
}关于 org.springframework.asm.ClassReader是ASM体系里面的内容了
ASM官网
关键对象/接口(Annotation)
ClassMetadata
class的元数据抽象
public interface ClassMetadata {
// 返回类名(注意返回的是最原始的那个className)
String getClassName();
//是否接口 抽象
boolean isInterface();
boolean isAbstract();
/**
*是否注解
*/
boolean isAnnotation();
// 是否允许创建, 不是接口且不是抽象类
default boolean isConcrete() {
return !(isInterface() || isAbstract());
}
boolean isFinal();
// 是否是独立的(能够创建对象的) 比如是Class, 或者内部类, 静态内部类
boolean isIndependent();
//是否封闭类
default boolean hasEnclosingClass() {
return (getEnclosingClassName() != null);
}
@Nullable
String getEnclosingClassName();
default boolean hasSuperClass() {
return (getSuperClassName() != null);
}
@Nullable
String getSuperClassName();
// 会把实现的所有接口名称都返回 具体依赖于Class#getSuperclass
String[] getInterfaceNames();
// 基于: Class#getDeclaredClasses 返回类中定义的公共, 私有, 保护的内部类
String[] getMemberClassNames();
}
Spring IOC 常用注解
@Configuration
@Configuration
通常配合@Bean 注解一起使用 作为配置类
Spring3.0 注解, 用于定义配置类, 可替换xml配置文件,初始化Spring容器,约等于
<Beans>...</Beans>注解的配置类有如下要求:
不可以是final类型; 不可以是匿名类; 嵌套的configuration必须是静态类;
- @Bean: 就是在spring配置文件中声明了一个bean
- 赋值为hello world,
- 方法返回类型就是bean的类型,
- 方法名是bean的id.
类似XML
<bean id="hello" class="String" />
(默认为单例, 可通过@Scope(“prototype”)指定,其他类同同几乎XML的所有方式都可以被注解替换 )
既然@Bean的作用是注册bean对象, 那么完全可以使用@Component, @Controller, @Service, @Repository等注解注册bean(在需要注册的类上加注解), 当然需要配置@ComponentScan注解进行自动扫描;
@Value注解
@Value的作用是通过注解将常量, 配置文件中的值, 其他bean的属性值注入到变量中, 作为变量的初始值;
支持如下方式的注入:
- 普通注入
@Value("张三")
private String name; // 注入普通字符串- bean属性, 系统属性, 表达式注入,使用@Value(”#{}”); bean属性注入需要注入者和被注入者属于同一个IOC容器, 或者父子IOC容器关系, 在同一个作用域内;
// 注入其他Bean属性: 注入beanInject对象的属性another, 类具体定义见下面
@Value("#{beanInject.another}")
private String fromAnotherBean;
// 注入操作系统属性
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName;
//注入表达式结果
@Value("#{T(java.lang.Math).random() * 100.0 }")
private double randomNumber;- 配置文件属性注入@Value(”${}”)
@Value("#{}") 读取配置文件中的值, 注入到变量中去; 配置文件分为默认配置文件application.properties和自定义配置文件
@Resource
@Resource: @Resource是JSR250规范的实现, 需要导入javax.annotation实现注入; @Resource可以作用在变量, setter方法上; @Resource是根据名称进行自动装配的, 一般会指定一个name属性;
参考 [JSR330 Spring ]https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-standard-annotations
@Qualifier
@Autowired 默认是根据类型进行注入的, 因此如果有多个类型一样的Bean候选者, 则需要限定其中一个候选者, 否则将抛出异常
@Qualifier("restTemplate2")
@Autowired
RestTemplate rest@Primary
当存在多个相同类型的 Bean, 例如, 多个DataSource, 多个JdbcTemplate时, 强烈建议总是使用 @Primary 把其中某一个Bean标识为”主要的”,
使用 @Autowired 注入时会首先使用被标记为 @Primary 的Bean;
相同类型的其他Bean, 每一个都需要用@Bean(name=“xxx”)标识名字, 并且, 在使用@Autowired注入时配合@Qualifier("xxx")指定注入的Bean的名字
Spring Framework 与 JDK 支持情况
- Spring Framework 7.x: JDK 17-25+
- Spring Framework 6.2: JDK 17-25
- Spring Framework 6.1: JDK 17-23
- Spring Framework 6.0: JDK 17-21
- Spring Framework 5.3: JDK 8-21 (as of 5.3.26)
- Spring Framework 5.2.x: JDK 8-15
- Spring Framework 5.1.x: JDK 8-12
- Spring Framework 5.0.x: JDK 8-10
- Spring Framework 4.3.x: JDK 6-8