「本文已参与 周末学习计划,点击查看详情 」
Spring从2.5开始支持基于注解的bean扫描,考虑到目前流行的SpringBoot框架也是大量采用了注解驱动开发,所以本文直接跨过xml配置,从注解驱动开始,一探究竟为什么加了@Service,就可以直接在Spring中注入并调用方法了?
Spring源码系列所有的源码都可以在我个人的Github仓库下载。
准备调试环境
基于上一篇文章的源码编译环境,我们新建了一个spring-learn模块,接下来就在这个模块里搞点事情。
UserService.java & UserServiceImpl.java
public interface UserService {
public String getUserName(String userId);
}
public class UserServiceImpl implements UserService {
@Override
public String getUserName(String userId) {
return userId.toUpperCase();
}
}
AnnotationConfig.java
@Configuration
public class AnnotationConfig {
@Bean
public UserService userServiceImpl(){
return new UserServiceImpl();
}
}
AnnotationContextMain.java
/**
* @description: 基于注解的Spring Ioc容器
* @author: Poppy
* @create: 2021-05-19 16:16
**/
public class AnnotationContextMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.poppy.ioc");
UserService userService = context.getBean(UserService.class);
System.out.println(userService.getUserName("poppy"));
}
}
执行main()方法,输出的结果POPPY
,从代码上看,无非就是new了一个AnnotationConfigApplicationContext,然后从这个Conntext中拿到了UserService的实例,并调用了getUserName()方法。接下来重点看下AnnotationConfigApplicationContext()的构造方法。
/**
* Create a new AnnotationConfigApplicationContext, scanning for bean definitions
* in the given packages and automatically refreshing the context.
* @param basePackages the packages to check for annotated classes
*/
public AnnotationConfigApplicationContext(String... basePackages) {
//01 调用父类的无参构造函数,调用初始化方法
this();
//02 扫描指定路径下面的BeanDefinition
scan(basePackages);
//03 完成整个容器的刷新(实例化,BeanPostProsser等)
refresh();
}
这三个方法就是整个容器的创建启动过程了,接下来分为3大块来分析具体的流程。
01初始化AnnotationConfigApplicationContext
1.init()
public AnnotationConfigApplicationContext() {
//调用父类无参的构建函数new出一个DefaultListableFactory
/**
* 1.1初始化基于注解的beanDefinition扫描器
* 把处理注解的bean定义 放入到容器中
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
//1.2初始化 基于classpath的beanDefinition扫描器 默认使用的是这个
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
1.1 主要完成 初始化注解后处理器 到BeanDefinitionMap中
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
//传递过来的 AnnotationConfigApplicationContext bean定义 容器
this.registry = registry;
/**
* 用于计算判断 {@link Conditional} 注解
*/
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
/**
* 1.1.1注册 所相关注解的后置处理器 到registry
*/
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
1.1.1
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
/**
* 注册处理 {@link Configuration} 后置处理器
*/
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
/**
* 注册处理 {@link Autowired} 后置处理器
*/
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
/**
* 注册处理 {@link Required} 后置处理器
*/
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
//@EventListener
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
1.2 初始化基于指定路径的包扫描器
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
// 初始化默认的包扫描过滤器,主要是 3类注解扫描
registerDefaultFilters();
}
setEnvironment(environment);
//设置资源加载器
setResourceLoader(resourceLoader);
}
注册默认的IncludeFilter,后面会用来筛选符合条件的bean
registerDefaultFilters()
protected void registerDefaultFilters() {
//加入扫描@Component注解的过滤器,这样就能扫到 @Component注解 以及其派生注解 @Controller,@Service,Repository...
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
//JSR-250规范的注解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
//JSR-330规范的注解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
到此完成了BeanFactory,注解后处理PostProcessor,AnnotationTypeFilter初始化。
02扫描所有的BeanDefinition
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
// 使用刚刚基于指定路径的 ClassPathBeanDefinitionScanner 扫描包
this.scanner.scan(basePackages);
}
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
/**
* 扫描 所有的 被@Component以及派生注解修饰的 beanDefinition (注意还没有生成bean)
* 判断一个类的时候 可以指定父类或者接口
*/
doScan(basePackages);
// Register annotation config processors, if necessary.
// 在上面初始AnnotatedBeanDefinitionReader 已经处理过了
if (this.includeAnnotationConfig) {
/**
* @link org.springframework.context.annotation.AnnotatedBeanDefinitionReader.AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)
*/
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
doSacn()
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通过Resource查找类路径下面候选的类
* 2.2.做一些基础的处理
* 2.3.把处理完成的BeanDefinition注册到BeanFactory
* 2.4.完成所有的类扫描
*/
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//绑定BeanDefinition与Scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//查看是否配置类是否指定bean的名称,如没指定则使用类名首字母小写
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//2.2 处理lazy、Autowire、DependencyOn、initMethod、enforceInitMethod、destroyMethod、enforceDestroyMethod、Primary、Role、Description这些逻辑的
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查BeanDefinition是否存在:初次扫描到的肯定是不存在的
if (checkCandidate(beanName, candidate)) {
// 用BeanDefinitionHolder再次包装BeanDefinition
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//检查scope是否创建,如未创建则进行创建
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//2.3 注册BeanDefinition到BeanFactory的BeanDefinitionMap中。
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
//2.4
return beanDefinitions;
}
2.1 扫描包findCandidateComponents()
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//2.1.1组装扫描路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//2.1.2扫描指定路径下面的所有类
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 {
/**
* 2.1.3元数据阅读器,获取类上的资源,类信息,注解信息
*/
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
/**
* 2.1.4【重要】 直接判断是否是需要装配的Bean组件
* 是:放入集合统一返回
* 否:过滤
*/
if (isCandidateComponent(metadataReader)) {
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;
}
2.1.2扫描的简单逻辑就是通过resourcePatternResolver解析指定路径下的所有类
2.1.3这是一个元数据阅读器MetadataReader可以获取类的ReSource,类元数据,还有注解元数据。门面设计模式
public interface MetadataReader {
/**
* Return the resource reference for the class file.
*/
Resource getResource();
/**
* Read basic class metadata for the underlying class.
*/
ClassMetadata getClassMetadata();
/**
* Read full annotation metadata for the underlying class,
* including metadata for annotated methods.
*/
AnnotationMetadata getAnnotationMetadata();
}
2.1.4判断是否是符合条件的bean
/**
* Determine whether the given class does not match any exclude filter
* and does match at least one include filter.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
* 判断 是否不匹配任意一个exclude filter
* 且匹配至少一个include filter
* 在判断是否满足@Condition条件
*/
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;
}
到此完成了候选Bean的扫描和判断。 2.3 把2.1中符合条件的BeanDefinition 注册到BeaFactory工厂的BeanDefinitionMap变量中
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 注册beanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//如果bean指定了别名还会注册别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
registry.registerBeanDefinition()
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
/**
* 所有的BeanDefinition都会放在beanDefinitionMap变量中
* 01 先判断是否已经存在 同名的BeanDefinition
* 1.1 存在判断是否能覆盖
* 1.2直接覆盖同名的Bean,不同类型也能覆盖
* 02不存在同名的BeanDefinition
* 2.1直接放入beanDefinitionMap,beanDefinitionNames变量中
* 2.2清理缓存
*/
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 不允许覆盖,然后又重复扫描到了 -> 抛出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + existingDefinition + "] bound.");
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
/**
* 用框架定义的 Bean 覆盖用户自定义的 Bean
* 这里看注释是这么翻译的,但是在实际SpringBoot项目中:
* 如果没有手动disableAutoConfig 好像都是用户自定义的配置类覆盖了框架自动装配的。还得试验下。??
*/
if (logger.isWarnEnabled()) {
logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isInfoEnabled()) {
logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//02 不存在同名的BeanDefinition
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 处理缓存
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
到此,完成了所有包扫描的工作。并且把BeanDefinition注入到了BeanFactory。注意,到此任然没有初始化Bean,全部都是Bean的包装BeanDefinition。 这里放一张调试的截图,截止scan()执行完成,AnnotationConfigApplicationContext容器的初始化情况。
03刷新容器
refresh()
刷新容器的内容较多,在下个章节阐述。