在看@Autowired注解源码之前,需要先了解一下现有的注入方式,才能更好的理解spring底层实现
本篇文章主要以**@Autowired寻找注入点、注入点进行注入**重点解析
分两种:
手动注入
自动注入
在XML中定义Bean时,就是手动注入,因为是程序员手动给某个属性指定了值。
<bean name="userService" class="com.luban.service.UserService">
<property name="orderService" ref="orderService"/>
bean>
<bean name="userService" class="com.luban.service.UserService">
<constructor-arg index="0" ref="orderService"/>
bean>
所以手动注入的底层也就是分为两种:
set方法注入
构造方法注入
自动注入又分为两种
XML的autowire自动注入
@Autowired注解的自动注入
在XML中,我们可以在定义一个Bean时去指定这个Bean的自动注入模式:
byType
byName
constructor
default
no
比如:
<bean id="userService" class="com.luban.service.UserService" autowire="byType"/>
这么写,表示Spring会自动的给userService中所有的属性自动赋值(不需要这个属性上有@Autowired注解,但需要这个属性有对应的set方法)。
@Autowired注解,是byType和byName的结合。
@Autowired注解可以写在
属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
而这种底层用到了:
属性注入
set方法注入
构造方法注入
autowireByName 和autowireByType底层逻辑基本差不多,区别就是一个根据类型,一个根据名称
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
干了啥?
遍历beanName属性名,根据属性名getBean,添加到pvs集合中
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 当前Bean中能进行自动注入的属性名
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍历每个属性名,获取getBean并且添加到pvs中
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
// 记录一下当前遍历的Bean被哪个bean依赖了(可以理解为propertyName=orderService,beanName=userService)
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
主要做了几件事情
1、底层获取PropertyDescriptor对象数组
2、遍历,筛选到满足可以自动注入的benaName集合,返回
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
PropertyValues pvs = mbd.getPropertyValues();
// 1、拿到当前类的所有set方法,setxxx,拿到的name就是xxx。
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
// 2、遍历
for (PropertyDescriptor pd : pds) {
// 什么样的属性能进行自动注入?
// 1.getWriteMethod---该类有对应的set方法
// 2.isExcludedFromDependencyCheck --- 忽略自动装配的给定依赖类型:例如,String。默认为none。
// 3.pvs.contains(pd.getName())---程序员自己没有给当前属性设置值
// 4.!BeanUtils.isSimpleProperty(pd.getPropertyType())---属性类型不是简单类型,比如int、Integer、int[]、Date、Number、URL....
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
// 把满足注入条件的加入到集合
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
AutowiredAnnotationBeanPostProcessor实现了上面的InstantiationAwareBeanPostProcessor接口
在属性填充代码逻辑中,上面这一段代码,会去调用AutowiredAnnotationBeanPostProcessor#postProcessProperties()做处理
这段代码主要是对bean里面包含了@Autowired注解的属性做处理
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 找到自动装配元数据
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;
}
这个方法会有多个地方调用
第一次调用的地方其实是在Bean后置处理器里面调用applyMergedBeanDefinitionPostProcessors,然后才是在属性填充时调用
这个方法主要是把类名称添加到缓存里
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 类名作为缓存key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 查看缓存里有没有类名key,第一次进来肯定是没有的
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 为空则进if,双重锁检测
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
//清除缓存
metadata.clear(pvs);
}
// 构建自动装配元数据,然后添加到缓存
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
主要做了几件事情
1、看你这个类型是不是一个基础类型
2.、遍历当前类下的属性,寻找注入点,看是否有有@Autowired & @Value注解的属性
3、然后确定required状态,然后添加到需要注入的集合里
4、遍历当前类下的方法,寻找注入点,看是否有有@Autowired & @Value注解的set方法
5、同2一致
6、while循环,查找父类有没有注入点,直到找到所有的注入点结束
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 检查有没有前缀是不是以"java.开头,如String,Integer等...基础类型,基础类型不会被注入
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 处理当前类下的属性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 有@Autowired & @Value注解的属性
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// 不是注入点,不会注入
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 判断注解是否包含required,一般情况这里都返回true
boolean required = determineRequiredStatus(ann);
// 添加到集合(里面包含需要依赖注入的属性)
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 处理当前类下的method方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 查找桥接方法,一般没有自己返回
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 查找是否有@Autowired & @Value注解的方法,
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// 不是注入点,不会注入
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
// 如果没有构造参数,则打印日志
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
// 判断注解是否包含required,一般情况这里都返回true
boolean required = determineRequiredStatus(ann);
//
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 添加到需要依赖注入的集合里
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 添加所有属性和method的需要依赖的bean
elements.addAll(0, currElements);
// 获取父类
targetClass = targetClass.getSuperclass();
}
// 循环直到没有父类为止,全部添加到一个集合里
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition()找出注入点并缓存,找注入点的流程为:
1、遍历当前类的所有的属性字段Field
2、查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段是一个注入点
3、如果字段是static的,则不进行注入
4、获取@Autowired中的required属性的值
5、将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。
6、遍历当前类的所有方法Method
7、判断当前Method是否是桥接方法,如果是找到原方法
8、查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点
9、如果方法是static的,则不进行注入
10、获取@Autowired中的required属性的值
11、将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中。
12、遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
13、最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。
@Component
@Scope("prototype")
public class OrderService {
}
@Component
@Scope("prototype")
public class UserService {
@Autowired
private static OrderService orderService;
public void test() {
System.out.println("test123");
}
}
看上面代码,UserService和OrderService都是原型Bean,假设Spring支持static字段进行自动注入,那么现在调用两次
UserService userService1 = (UserService) context.getBean("userService");
UserService userService2 = (UserService) context.getBean("userService");
问此时,userService1的orderService值是什么?还是它自己注入的值吗?
答案是:不是,一旦userService2 创建好了之后,static orderService字段的值就发生了修改了,从而出现bug。
public interface UserInterface<T> {
void setOrderService(T t);
}
@Component
public class UserService implements UserInterface<OrderService> {
private OrderService orderService;
@Override
@Autowired
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void test() {
System.out.println("test123");
}
}
UserService对应的字节码为:
// class version 52.0 (52)
// access flags 0x21
// signature Ljava/lang/Object;Lcom/ljc/service/UserInterface;
// declaration: com/ljc/service/UserService implements com.ljc.service.UserInterface
public class com/ljc/service/UserService implements com/ljc/service/UserInterface {
// compiled from: UserService.java
@Lorg/springframework/stereotype/Component;()
// access flags 0x2
private Lcom/ljc/service/OrderService; orderService
// access flags 0x1
public <init>()V
L0
LINENUMBER 12 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public setOrderService(Lcom/ljc/service/OrderService;)V
@Lorg/springframework/beans/factory/annotation/Autowired;()
L0
LINENUMBER 19 L0
ALOAD 0
ALOAD 1
PUTFIELD com/ljc/service/UserService.orderService : Lcom/ljc/service/OrderService;
L1
LINENUMBER 20 L1
RETURN
L2
LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L2 0
LOCALVARIABLE orderService Lcom/ljc/service/OrderService; L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
// access flags 0x1
public test()V
L0
LINENUMBER 23 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "test123"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 24 L1
RETURN
L2
LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x1041
public synthetic bridge setOrderService(Ljava/lang/Object;)V
@Lorg/springframework/beans/factory/annotation/Autowired;()
L0
LINENUMBER 11 L0
ALOAD 0
ALOAD 1
CHECKCAST com/ljc/service/OrderService
INVOKEVIRTUAL com/ljc/service/UserService.setOrderService (Lcom/ljc/service/OrderService;)V
RETURN
L1
LOCALVARIABLE this Lcom/ljc/service/UserService; L0 L1 0
MAXSTACK = 2
MAXLOCALS = 2
}
可以看到在UserSerivce的字节码中有两个setOrderService方法:
public setOrderService(Lcom/ljc/service/OrderService;)V
public synthetic bridge setOrderService(Ljava/lang/Object;)V
并且都是存在@Autowired注解的。
所以在Spring中需要处理这种情况**,当遍历到桥接方法时,得找到原方法**。
在上一步构建好注入点后,寻找开始依赖注入!
Spring在AutowiredAnnotationBeanPostProcessor的**postProcessProperties()**方法中,会遍历所找到的注入点依次进行注入。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 遍历每个注入点,开始依赖注入
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
需要注意上面的
element.inject(target, beanName, pvs);
并不是直接看父类的实现,在@Autowired实现这里 只需要看 field和method的2个实现即可,@Resource的实现是用的父类实现
主要做了几件事情
1、遍历所有的AutowiredFieldElement对象。
2、将对应的字段封装为DependencyDescriptor对象。
3、调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
4、将DependencyDescriptor对象和所找到的结果对象beanName封装成一个**ShortcutDependencyDescriptor对象作为缓存,**比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
5、将结果对象赋值给字段。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
// 默认是false,第一次进来肯定不会进if
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
// 将对应的字段封装为DependencyDescriptor对象(创建依赖描述符对象)
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
// 设置calss
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
// 获取类型转换器
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) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
// 创建缓存对象,方便缓存
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
// 缓存
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
// 将结果对象赋值给字段
field.set(bean, value);
}
}
}
和字段注入实现逻辑类似…
主要做了几件事情
1、遍历所有的AutowiredMethodElement对象
2、遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
3、将MethodParameter对象封装为DependencyDescriptor对象
4、调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
5、将DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
6、利用反射将找到的所有结果对象传给当前方法,并执行。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
if (checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
// Shortcut for avoiding synchronization...
arguments = resolveCachedArguments(beanName);
}
else {
int argumentCount = method.getParameterCount();
arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
// 每个参数封装成MethodParameter对象
MethodParameter methodParam = new MethodParameter(method, i);
// 将MethodParameter对象封装为DependencyDescriptor对象
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
// 进行依赖查找,找到当前方法参数所匹配的Bean对象
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
// 封装缓存对象
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
}
else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
if (arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
// 注入
method.invoke(bean, arguments);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}