目录
1.前言
上一篇文章中《Spring 控制反转(IOC)及依赖注入(DI)》https://blog.csdn.net/luofen521/article/details/120273369介绍了Spring 中IOC及DI的一些概念,并主要分析了XML形式setter方式注入的源码,这篇文章主要介绍使用@Autowired注解字段注入的方式来实现依赖注入的源码。
2.使用注解实现依赖注入
首先我们定义一个StudentDao,用于模拟操作数据库的操作接口,定义了getStudent方法,如下:
public interface StudentDao {
Student getStudent();
}
然后我们创建一个实现类StudentDaoImpl,在getStudent方法模拟了从数据库获取数据的操作,并在接口的定义加上@Repository注解,如下:
@Repository
public class StudentDaoImpl implements StudentDao {
@Override
public Student getStudent() {
Student student = new Student();
student.setId(24);
student.setName("zhangsan");
return student;
}
}
Dao层好了,我们现在来定义Service层
首先,创建一个SudentService接口,并定义了getStudent方法,如下:
public interface StudentService {
Student getStudent();
}
然后创建一个实现类StudentServiceImpl,在类的定义上加上@Service注解,并引入了StudentDao,用于调用Dao层的方法,在定义StudentDao时加上了@Resource注解,代码如下:
@Service
public class StudentServiceImpl implements StudentService{
@Resource
StudentDao studentDao;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
到此,Service层也定义好了,我们在测试单元中去验证下,首先也是定义了StudentService ,并在定义上面加上了@Resource注解,然后调用其getStudent方法,代码如下:
@SpringBootTest
class ApplicationTests {
@Resource
StudentService studentService;
@Test
void contextLoads() {
Student student = studentService.getStudent();
System.out.println("学生id:" + student.getId());
System.out.println("学生姓名:" + student.getName());
}
}
运行结果如下:
可以看到,我们没有手动地去创建Servcie、Dao层对应类的对象,而是通过@Repository、@Service、@Resource等注解完成了Bean的创建和关联。
接下来我们看看这些注解的含义
3. 依赖注入相关的注解
3.1 为什么会需要使用这些注解?
在Spring早期的版本,是使用配置文件来管理bean的定义,当项目越来越复杂时,配置文件的管理成了一个很艰巨的任务,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book" class="Book" scope="singleton">
<property name="bookName" value="平凡的世界"/>
<property name="author" value="路遥"/>
</bean>
<bean id="book2" class="Book2" scope="prototype">
<property name="bookName" value="平凡的世界"/>
<property name="author" value="路遥"/>
</bean>
<bean id="bookService" class="BookService">
<property name="book" ref="book" />
</bean>
</beans>
所以在Spring后面的版本,逐渐引入了注解来标识哪些类需要由Spring容器来管理,这样做主要是为了管理方便。
看下面这样,是不是要简单得多?
@Service
public class StudentServiceImpl implements StudentService {
}
3.2 相关的注解
3.2.1 类的定义注解
其实除了上述用到的Service、Repository注解,还有@Controller、@Component也是常用的注解,它们用于定义类时标识类对象的创建有Spring来统一管理,我们先来看看他们的定义
@Controller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Service
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Repository
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
会发现@Controller、@Service、@Repository除了名字不同,实现一模一样,并且定义上都使用了 @Component注解。
所以可以这么理解,@Controller、@Service、@Repository =( @Component + 特定的功能),但他们在依赖注入这方面的功能是一样的。
@RestController
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
而RestController结合了@Controller和@ReponseBody,不需要再在方法的返回上加@ReponseBody,下面是@Controller和@RestController的对比
@Controller
@Controller
@RequestMapping("books")
public class SimpleBookController {
@GetMapping("/{id}", produces = "application/json")
public @ResponseBody Book getBook(@PathVariable int id) {
return findBookById(id);
}
private Book findBookById(int id) {
// ...
}
}
@RestController
@RestController
@RequestMapping("books-rest")
public class SimpleBookRestController {
@GetMapping("/{id}", produces = "application/json")
public Book getBook(@PathVariable int id) {
return findBookById(id);
}
private Book findBookById(int id) {
// ...
}
}
总结如下:
序号 | 注解 | 含义 |
1 | @Component | 通用的注解,可以定义Spring管理的任务组件 |
2 | @Controller | 用于表现层(spring-mvc中使用),具有转发、重定向等特性 |
3 | @Service | 用于业务逻辑层 |
4 | @Repository | 用于持久层,并自动处理数据库操作产生的异常 |
5 | @RestControler | 用于表现层,集合了@Controller和@ReponseBody的特性 |
上述主要是类定义时,用到的注解,定义好之后,我们还需要在使用的地方使用引用的注解。
3.2.2 注入相关的注解
上述用到了@Resource注解来把我们需要的对象进行注入,其实常用的还有@Autowired
在上述的代码中,我们使用@Autowired来代替@Resource也是可以的,代码如下:
@Service
public class StudentServiceImpl implements StudentService{
@Autowired
StudentDao studentDao;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
那@Resouce和@Autowired有什么区别呢?
首先,我们看看他们的定义,可以看到Resource是java自带的属性;而Autowired是springframework提供的注解
package javax.annotation;
public @interface Resource {
package org.springframework.beans.factory.annotation;
public @interface Autowired {
其次,@Autowired是根据类型来装配依赖对象,但是如果我们同一个类型有多个对象会怎么样?比如我们把上面的StudentDaoImpl类再复制一个放到新建的dao文件夹下,这时候就会有有2个类型为StudentDaoImpl的类,这时候我们运行程序就会报下面的错误:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException:
Failed to parse configuration class [com.yc.springboot.Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'studentDaoImpl' for bean class [com.yc.springboot.dao.StudentDaoImpl]
conflicts with existing, non-compatible bean definition of same name and class [com.yc.springboot.StudentDaoImpl]
... 63 more
可以看到,在装配StudentDao时,发现有两个相同类型的实现类,所以报错了,这个时候就需要用到@Qualifier注解。首先,我们在dao下的StudentDaoImpl中写value值“StudentDaoImpl2 ”,并设置name为“zhangsan 2”,代码如下:
package com.yc.springboot.dao;
import com.yc.springboot.Student;
import com.yc.springboot.StudentDao;
import org.springframework.stereotype.Repository;
@Repository("StudentDaoImpl2")
public class StudentDaoImpl implements StudentDao {
@Override
public Student getStudent() {
Student student = new Student();
student.setId(24);
student.setName("zhangsan 2");
return student;
}
}
然后在StudentServiceImpl中引入时,用@Qualifier("StudentDaoImpl2")来指定我们希望装配的对象,如下:
@Service
public class StudentServiceImpl implements StudentService{
@Autowired
@Qualifier("StudentDaoImpl2")
StudentDao studentDao;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
运行结果如下,可以看到,这个时候打印出来的名字为“zhangsan 2”,也就是说我们通过@Qualifier和@Autowired搭配使用,实现了按name来装配的效果
而@Resource默认就是byName来自动装配,我们还是用之前的StudentDaoImpl2来举例,我们可以直接在定义时,给@Resource制定name为“StudentDaoImpl2”,如下:
@Service
public class StudentServiceImpl implements StudentService{
@Resource(name="StudentDaoImpl2")
StudentDao studentDao;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
运行结果跟使用@Qualifier和@Autowired搭配使用是一致的。
其实,@Resource支持按照byName来装配的,也支持通过type来按照byType来装配,如下:
@Service
public class StudentServiceImpl implements StudentService{
@Resource(type = StudentDaoImpl.class)
StudentDao studentDao;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
4. 源码分析
我们接下来看看源码,是怎么实现的
首先,我们要创建一个AppConfig作为配置文件,并增加注解@ComponentScan用于指定需要进行组件扫描的包
@Configuration
@ComponentScan("com.yc.springframework")
public class AppConfig {
}
然后在我们的测试类中,去初始化ioc容器,然后获取StudentService,并调用其方法
public class IOCAnnotatedTest {
public static void main(String[] args) {
//初始化IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//获取bean
StudentService studentService = applicationContext.getBean(StudentService.class);
//调用bean的方法
Student student = studentService.getStudent();
System.out.println("学生id:" + student.getId());
System.out.println("学生姓名:" + student.getName());
}
}
而在StudentServiceImpl的定义中,使用了@Service声明,并使用@Autowired来自动装配StudentDao对象,如下:
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
StudentDao studentDao;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
4.1 初始化过程
首先是通过下面这行代码完成了IOC容器的初始化
//初始化IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
构造方法如下所示
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
看起来是不是跟xml实现依赖注入的方式很像,这里主要还是看refresh方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//省略部分代码...
try {
//调用这个上下文中注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
//删除无关代码
}
finally {
resetCommonCaches();
}
}
}
最后会调用到PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//省略部分代码
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//调用BeanDefinition注册处理器
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//省略部分代码...
}
调用了invokeBeanDefinitionRegistryPostProcessors方法,代码如下:
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
这里其实是调用了ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法,如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
主要是调用了processConfigBeanDefinitions方法对配置进行了解析,代码如下:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
do {
//对候选者进行解析
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<String>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null) {
if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
首先是调用了ConfigurationClassParser的parse方法
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
//对注解BeanDefinition进行解析
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
这里会继续调用ConfigurationClassParser的parse方法
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
直接调用了同类中的processConfigurationClass方法
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
//对于配置的class进行处理
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
调用了doProcessConfigurationClass对配置类进行解析
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//省略了部分代码
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//省略部分代码...
// No superclass -> processing is complete
return null;
}
这里会调用ComponentScanAnnotationParser的parse方法
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//省略部分代码
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
实际上是调用了ClassPathBeanDefinitionScanner的doScan方法
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) {
//通过扫描basePackages得到需要的Bean定义
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);
}
}
}
return beanDefinitions;
}
我们先看ClassPathScanningCandidateComponentProvider的findCandidateComponents选择候选的组件
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//得到packageScan路径下所有的类
Resource[] resources = this.resourcePatternResolver.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 metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
//判断是否为候选组件
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
//加入到BeanDefinition列表,作为bean的候选名单
candidates.add(sbd);
}
}
//省略部分代码
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
得到我们需要加载的组件后,doScan方法中遍历了Set<BeanDefinition>,并调用了registerBeanDefinition方法,最后会调用到DefaultListableBeanFactory的registerBeanDefinition方法,具体如下:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//如果已经存在定义了,则日志输出警告
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
//把定义存到Map中
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(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 (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
会发现这里会把BeanDefinition存到beanDefinitionMap中,看看它的定义
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
它是一个ConcurrentHashMap对象,后面再创建Bean时,会从这个集合中获取需要创建的Bean
这个时候就完成了哪些类需要初始化的筛选,接下来要真正地来初始化Bean了,我们再回到AbstractApplicationContext类的refresh方法,其中下面这段代码是完成单例的初始化的
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
后面的流程,就跟之前xml实现依赖注入的流程一致了,就不做详细展开了。可以看上一篇文章。
可以看到使用注解和使用xml实现依赖注入的方式,只有在解析Bean定义的时候不同,后面的创建Bean及初始化流程是一致的。
4.2 Bean的获取
我们也是通过getBean方法获取Bean
StudentService studentService = applicationContext.getBean(StudentService.class);
我们看看
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
这里调用的是DefaultListableBeanFactory的getBean方法
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
@Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
//获取Bean的持有类
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
BeanFactory parent = getParentBeanFactory();
if (parent != null) {
return parent.getBean(requiredType, args);
}
throw new NoSuchBeanDefinitionException(requiredType);
}
这里是直接调用了resolveNamedBean方法获取Bean的持有类
@SuppressWarnings("unchecked")
private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, Object... args) throws BeansException {
//省略部分代码...
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
//调用getBean方法获取Bean
return new NamedBeanHolder<T>(beanName, getBean(beanName, requiredType, args));
}
//省略部分代码
return null;
}
这里调用了AbstractBeanFactory的getBean方法,这就回到了xml实现注解获取Bean的流程,就不详细展开介绍了。
4.3 Autowired的工作原理
我们StudentServiceImpl中的StudentDao是通过使用Autowired注解进行注入的,并增加一个Student 对象,但是不增加@Autowired注解,代码如下:
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
StudentDao studentDao;
Student student;
@Override
public Student getStudent() {
return studentDao.getStudent();
}
}
我们来看看Autowired是怎么工作的,我们需要回到创建Beand的地方AbstractAutowireCapableBeanFactory的doCreateBean方法中,代码如下:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// 允许后置处理器来处理bean
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//省略部分代码
return exposedObject;
}
我们可以看到主要是调用了applyMergedBeanDefinitionPostProcessors方法
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
这里是把后置处理器都拿出来,然后处理bean,这里是调用的AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
//找到自动注解的元数据
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
这里就是调用了findAutowiringMetadata方法去找到哪些需要自动注入的源数据
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
//构建自动注入的元数据
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for autowiring metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
这里主要是判断内存缓存中是否存在,不存在则调用buildAutowiringMetadata方法去构建,并且加入到缓存中,我们继续看buildAutowiringMetadata方法:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements =
new LinkedList<InjectionMetadata.InjectedElement>();
//处理带有注解的属性
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
//找到需要注入的属性
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
//主要注入的属性
currElements.add(new AutowiredFieldElement(field, required));
}
}
});
//处理带有注解的方法
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
//构造一个InjectionMetadata返回,需要注入的元素在elements中
return new InjectionMetadata(clazz, elements);
}
先调用doWithLocalFields方法处理带有注解的属性
public static void doWithLocalFields(Class<?> clazz, ReflectionUtils.FieldCallback fc) {
//找到当前类中的属性
Field[] var2 = getDeclaredFields(clazz);
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Field field = var2[var4];
try {
//回调doWith方法,对每个属性进行处理
fc.doWith(field);
} catch (IllegalAccessException var7) {
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + var7);
}
}
}
我们继续看回调的doWith方法
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
//找到属性上带的注解
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
//如果不为null,则加入到elements中
currElements.add(new AutowiredFieldElement(field, required));
}
}
});
先调用findAutowiredAnnotation方法得到当前属性上的注解,如果我们带有@Autowired、@Value,则会获取到对应的值;如果没有注解,则为null;当有值时,把属性当做参数,构造一个AutowiredFieldElement对象存入到elements中
下面是对带有注解的方法的处理,流程跟带有属性带有注解类似就不做解释了,然后再把得到的通过构造一个InjectionMetadata对象返回,这个对象里带有了那些属性需要自动注入,这样就完成了当前类中的哪些属性需要自动注入,我们在AutowiredAnnotationBeanPostProcessor类的findAutowiringMetadata方法中buildAutowiringMetadata处增加断点,我们单步调试:
可以看到,需要注解的元数据包含了增加了@Autowired的studentDao,但是不包含没有注解的Book对象
这样就完成了查找当前对象中哪些属性是需要自动注入的,但是具体什么时候注入的呢?我们继续往下看,我们回到AbstractAutowireCapableBeanFactory类中的doCreateBean方法,在调用createBeanInstance方法创建实例、applyMergedBeanDefinitionPostProcessors方法找到哪些需要自动注入的属性后,然后调用populateBean方法进行对象的初始化
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
//省略部分代码
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
//遍历后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//给属性赋值
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
applyPropertyValues(beanName, mbd, bw, pvs);
}
我们来看下AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法,如下:
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//获取需要自动注入的属性
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//完成自动注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
findAutowiringMetadata方法就是通过beanName从缓存中获取到需要自动装配的属性,而在之前的流程我们说到了如果查找到需要自动注入的属性,并且把它们放到了缓存中。拿StudentServiceImpl对象的创建为例,这里是studentDao,然后调用InjectionMetadata的inject方法,如下:
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
//完成单个属性的注入
element.inject(target, beanName, pvs);
}
}
}
这里就是遍历了需要自动装配的属性,然后调用的是AutowiredFieldElement的inject方法完成每个属性的初始化,如下:
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//获取到属性对应的对象,这之前创建bean时,已经完成了创建
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
//通过反射给属性赋值
field.set(bean, value);
}
}
}
先是调用beanFactory.resolveDependency方法,从Bean工厂中获取到属性对应的Bean对象,如StudentServiceImpl中的studentDao对象,最后调用field.set来为StudentServiceImpl中的studentDao属性赋值,这样就完成了StudentServiceImpl中的studentDao对象的自动装配
4.4 如果确保被自动装配的对象在装配时已经完成初始化?
我们刚才为StudentServiceImpl中的studentDao对象完成自动装配时,StudentDaoImpl已经完成了初始化,是因为IOC在初始化组件时,是扫描指定目录后,根据类名全路径依次初始化的,这样StudentDaoImpl正好在StudentServiceImpl前面完成初始化,如果我们把StudentDaoImpl的类名改下,改成StudentZDaoImpl,代码如下:
@Repository
public class StudentZDaoImpl implements StudentDao {
流程是怎么样的呢?我们回到AutowiredFieldElement类中的inject方法中,
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//获得属性对应的对象
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
//省略部分代码
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
主要是通过DefaultListableBeanFactory的resolveDependency来获得属性的对象,我们来看看这个方法
@Override
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (xxx)
//省略部分代码
}
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
//得到依赖的对象
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
主要是调用了doResolveDependency方法
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
//主要看最后这里
return (instanceCandidate instanceof Class ?
descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
调用了DependencyDescriptor的resolveCandidate方法
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName, requiredType);
}
这里就回到了熟悉的配方了,通过beanName从Bean工厂中获取Bean,如果存在则直接返回已存在的Bean;如果不存在,则走创建的流程。
这里的StudentZDaoImpl此时就不存在,会先去创建,然后自动装配到StudentServiceImpl中的studentDao上。
4.5 如果解决循环依赖问题
上面讲到如果一个类依赖另外一个类,如果发现依赖的类还没创建,会去创建,但是如果要创建的类又依赖于当前的类会怎么样呢?会造成循环依赖的问题么?
比如我们定义一个A,交给容器管理,但是依赖了B
@Component
public class A {
@Autowired
private B b;
}
B的定义如下,B同样也依赖了A
@Service
public class B {
@Autowired
private A a;
}
Spring是怎么解决这个问题的呢?其实上面的分析流程已经能看出大概了
我们先看创建对象的过程主要是AbstractAutowireCapableBeanFactory中的doCreateBean方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 初始化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//2. 缓存半成品bean及bean工厂,以便解决循环依赖的问题
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//3. 初始化bean的实例(为属性赋值)
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
return exposedObject;
}
上面的流程主要分为3步:
- 实例化bean
- 把bean工厂缓存起来
- 初始化bean(为属性赋值)
我们看看addSingletonFactory方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
//把bean工厂放到缓存中
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
然后我们看下初始化B时,要给其属性a赋值的流程,主要是DefaultSingletonBeanRegistry中的getSingleton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从成品bean的缓存中获取对象
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从提前曝光未成品的bean中获取对象
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//获取到相应的bean工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//提前曝光bean实例,主要用于解决AOP循环依赖
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这里涉及到三级缓存:
- singletonObjects:成品bean
- earlySingletonObjects:提前暴露的bean(半成品bean)
- singletonFactory:bean工厂,用于提前暴露bean实例
整个流程就是先创建了A类的对象a,把bean工厂放入到缓存中;然后为A的属性b赋值,发现b不存在则创建B对象,创建完以后给B中的a赋值,从缓存中得到了A的bean工厂并得到半成品的a,完成了B的实例化,然后完成A中b的赋值,进而完成了A的实例化。于是AOP的循环依赖的问题得到了解决。
流程图如下: