本篇博客主要为spring专栏的spring-ioc 核心之springbean的装配错误纠正
https://blog.csdn.net/qq_38108719/article/details/99674379
纠正如下
@Autowired和@Resource不属于自动装配模型中的任意一种。本篇博客会有所涉及,后期会有源码验证
有兴趣的朋友可以看一下spring的内置处理器其中的有两个是专门解析@Autowired和@Resource这两个注解的。
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
首先根据spring官网提到的spring框架中inversion of control的注入方式只有setter 方法 和 构造方法
再看看提到的注入模型(4种)
那么这四种我们是如何使用的呢,spring 1.0版本所提供的xml形式配置的,为该文件中所有的bean如下
或者为单个bean如下
那我们可以知道一点的就是只有xml的配置方式才能使用自动装配模型
那么为什么@Autowired和@Resource不是呢。
我们在网上找@Autowired和@Resource的区别的时候,会提到@Autowired是先bytype再byname(set方法名字)
而@Resource是先byname再bytype,找不到就会报错。
那么我们现在就往下看到底是根据装配模型的byname 和 bytype,还是根据一种技术通过name 和 type 方式进行查找呢。
首先我们知道spring框架提供的这些注解是在spring2.5以后更新的
而spring官网中也并没有提到这两个注解使用了自动装配模型中的任意一点,如图我们可以进去看
我们现在用代码来解释的问题是@Autowired和@Resource这两个注解并没有使用到自动注入模型中的任意一种
环境一 spring传统的xml形式,来测试自动注入模型中的一种bytype
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
" default-autowire="byType">
<context:component-scan base-package="org.springframework.work2"></context:component-scan>
<bean id="uService" class="org.springframework.work2.service.UService" >
</bean>
<bean id="tService" class="org.springframework.work2.service.TService">
</bean>
</beans>
public class TService{
UService uService;
public UService getUService() {
return this.uService;
}
public void setUService(UService uService) {
this.uService = uService;
}
}
public class UService {
}
public class Main {
public static void main(String[] args) {
//AnnotationConfigApplicationContext cxc = new AnnotationConfigApplicationContext(AppConfig.class);
ClassPathXmlApplicationContext cxc = new ClassPathXmlApplicationContext("classpath:spring2.xml");
TService tService = (TService) cxc.getBean("tService");
System.out.println(tService.getUService());
}
}
我们需要的不是打印结果,毫无疑问是能正常注入的。我们点进源码中看,调用链为
org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons
org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.AbstractBeanFactory#createBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
我们先设置好断点再重新断点点进来
我们通过后置处理器来看一看这个bean的注入模型是什么
而我们刚好在xml配置自动装配模型就是bytype。
我们现在看第二种环境 测试注解@Autowired和@Resource
环境二 使用注解的形式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="org.springframework.work2"></context:component-scan>
<bean id="uService" class="org.springframework.work2.service.UService" >
</bean>
<bean id="tService" class="org.springframework.work2.service.TService">
</bean>
</beans>
package org.springframework.work2.service;
import org.springframework.stereotype.Component;
public class UService {
}
package org.springframework.work2.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
public class TService{
@Autowired
UService uService;
public UService getUService() {
return this.uService;
}
public void setUService(UService uService) {
this.uService = uService;
}
}
package org.springframework.work2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.work2.app.AppConfig;
import org.springframework.work2.service.TService;
import org.springframework.work2.service.UService;
public class Main {
public static void main(String[] args) {
//AnnotationConfigApplicationContext cxc = new AnnotationConfigApplicationContext(AppConfig.class);
ClassPathXmlApplicationContext cxc = new ClassPathXmlApplicationContext("classpath:spring2.xml");
TService tService = (TService) cxc.getBean("tService");
System.out.println(tService.getUService());
}
}
同样的断点同样的调用链,我们只看这两种注解的最后调用方法
我们再来打印看一下这个bean的装配模型
当然这个装配模型我们也可以在这个后置处理器中去手动设置为bytype或者是byname
beanDefinition.setAutowireMode(0); 0-1-2-3-4...
这边两个处理器就是上面提到过的解析@Autowired和@Resource两个注解的处理器。
很显然没有走bytype或者byname的方法。后面的博客也会证明这两个注解@Autowired和@Resource使用的注入技术是type和name 与 自动注入模型毫无关联。