Spring源码解析-基于注解依赖注入
在spring2.5版本提供了注解的依赖注入功能,可以减少对xml配置。
主要使用的是
AnnotationConfigApplicationContext: 一个注解配置上下文
AutowiredAnnotationBeanPostProcessor: spring提供的用于这一目的的BeanPostProcessor实现,用来检查当前对象是否有@Autowired标注的依赖注入。 项目中除了使用@Autowired之外,还可以选择JSR250的一些注解例如@Resource大致和@Autowired相同。
CommonAnnotationBeanPostProcessor:JSR250也需要BeanPostProcessor,spring实现类了。
在spring配置文件中添加<context:annotation-config/>可以将这些processor添加到spring容器中。
另外使用注解的方式还需要一个classpath-scanning功能,使用这一功能只需要在配置文件中添加<context:component-scan base-package='com.xx.xx'>
@Component注解使用太宽泛,细分了@Controller,@Service等标注。 简单示例
@Component
public class AnnotationDemo { public void printInfo(){
System.out.println(this.getClass());
}
}
@Component
public class AnnotationDemo2 { public void printInfo(){
System.out.println(this.getClass());
}
}
测试类
@Test
public void testAnnotationInject(){
ApplicationContext context = new AnnotationConfigApplicationContext("org.lzyer.test");
//指定某些类
//ApplicationContext context = new AnnotationConfigApplicationContext(AnnotationDemo.class,AnnotationDemo2.class);
AnnotationDemo ad = context.getBean(AnnotationDemo.class);
AnnotationDemo2 ad2 = context.getBean(AnnotationDemo2.class);
ad.printInfo();
ad2.printInfo();
}
方式一为加载包下带注解的类。方式二是指定某些类。
运行结果:
class org.lzyer.test.AnnotationDemo
class org.lzyer.test.AnnotationDemo2
注入流程

/**
* 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) {
this();
scan(basePackages);//扫描包
refresh();//调用AbstractApplicationContext中的refresh方法
}
/**
* Perform a scan within the specified base packages.
* @param basePackages the packages to check for annotated classes
* @return number of beans registered
*/
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); doScan(basePackages);//扫描 // Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
} return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* <p>This method does <i>not</i> register an annotation config processor
* but rather leaves this up to the caller.
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (String basePackage : basePackages) {//遍历所有的包
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);
registerBeanDefinition(definitionHolder, this.registry);//注册beandefinition
}
}
}
return beanDefinitions;
}
/**
* Scan the class path for candidate components.
* @param basePackage the package to check for annotated classes
* @return a corresponding Set of autodetected bean definitions
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + this.resourcePattern;//补充路径
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {//遍历Resource
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {//通过asm获取class,暂且不研究asm
MetadataReader metadataReader = this.metadataReaderFactory.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个判断条件。
/**
* Determine whether the given bean definition qualifies as candidate.
* <p>The default implementation checks whether the class is concrete
* (i.e. not abstract and not an interface). Can be overridden in subclasses.
* @param beanDefinition the bean definition to check
* @return whether the bean definition qualifies as a candidate component
*/
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
}
进行匹配。
/**
* 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
*/
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return isConditionMatch(metadataReader);
}
}
return false;
}
@Override
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
查看hasAnnotation和 hasMetaAnnotation方法。
@Override
public boolean hasAnnotation(String annotationType) {
return this.annotationSet.contains(annotationType);
} @Override
public boolean hasMetaAnnotation(String metaAnnotationType) {
Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
for (Set<String> metaTypes : allMetaTypes) {
if (metaTypes.contains(metaAnnotationType)) {
return true;
}
}
return false;
}
annotationSet包含的是注解,
metaAnnotationMap的key为注解,value是一个set。
Spring源码解析-基于注解依赖注入的更多相关文章
- Spring 源码分析之 bean 依赖注入原理(注入属性)
最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...
- .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着 ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
- Spring IoC 源码分析 (基于注解) 之 包扫描
在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...
- Spring源码学习笔记9——构造器注入及其循环依赖
Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...
- Spring源码解析——循环依赖的解决方案
一.前言 承接<Spring源码解析--创建bean>.<Spring源码解析--创建bean的实例>,我们今天接着聊聊,循环依赖的解决方案,即创建bean的ObjectFac ...
- Spring源码解析之BeanFactoryPostProcessor(三)
在上一章中笔者介绍了refresh()的<1>处是如何获取beanFactory对象,下面我们要来学习refresh()方法的<2>处是如何调用invokeBeanFactor ...
- spring 源码解析
1. [文件] spring源码.txt ~ 15B 下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB 下载( ...
- Spring源码-IOC部分-循环依赖-用实例证明去掉二级缓存会出现什么问题【7】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
随机推荐
- HTTP学习之HTTP基础
学习HTTP技术,首先要了解它的在web通信中有哪些特点,起到什么作用.有哪些规范.都有什么功能. HTTP的特点 HTTP使用的是一种可靠的.快速响应的数据传输协议,用户一旦发起请求,Web服务器可 ...
- python递归函数(计算阶乘)
def f1(x,x1=1): if x == 1: return x1 #x1这个值为我们所需要的值,所以返回 x1 *= x r = f1(x-1,x1) #r接收返回值,并在下面接着返回 ret ...
- 【NOIP-2017PJ】图书管理员
图书管理员 题目描述 图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个 正整数. 每位借书的读者手中有一个需求码,这个需求码也是一个正整数.如果一本书的图 书编码恰好以读者的需 ...
- 如何将h5网页改成微信网页
1.如何将h5网页改成微信网页 1.设置安全域名 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”. 备注:登录后可在“开发者中心”查看对 ...
- P1886 滑动窗口(单调队列)
P1886 滑动窗口 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: ...
- stm32--FatFs调试过程(SPIFlash)
移植方法参见我的另一篇博客:<stm32--FatFs移植(SPIFlash)>. 本文仅记录在初次移植完成后,遇到的问题,和解决的过程. 调试记录: 问题1:f_open返回3,即磁盘没 ...
- 区分Oracle的数据库,实例,服务名,SID
文章摘自:http://www.zhetao.com/content240 感谢分享O(∩_∩)O~ 在实际的开发应用中,关于Oracle数据库,经常听见有人说建立一个数据库,建立一个Instance ...
- anaconda虚拟环境操作
1.首先在所在系统中安装Anaconda.可以打开命令行输入conda -V检验是否安装以及当前conda的版本. 2.conda常用的命令. 1)conda list 查看安装了哪些包. 2)con ...
- html简单的分享功能
超级简单的分享. 包括:QQ.QQ空间.新浪微博.腾讯微博,微信(只是一个二维码): 1.首先是html代码: (前端我并不太会,一直用的都是bootstrap) <div class=&quo ...
- Asp.NET Core2.0与 EF的ABP框架入门视频教程
https://ke.qq.com/course/287301?from=qqchat&ADUIN=1187219916&ADSESSION=1522716499&ADTAG= ...