MacBook pro
java 8
springboot 2.0+
学习笔记
今天参考Spring基础(2):放弃XML,走向注解,
这篇文章温习spring时,对@Autowired
注入方式产生了疑惑。
因为我写了一个如下类:
package com.supper.javaconfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author yutao
* @since 2020/4/13 3:44 下午
*/
@Component
public class PersonC {
@Autowired
private CarC carC;
public CarC getCarC() {
return carC;
}
@Override
public String toString() {
return "PersonC{" +
"carC=" + carC +
'}';
}
}
package com.supper.javaconfig;
import org.springframework.stereotype.Component;
/**
* @author yutao
* @since 2020/4/13 3:44 下午
*/
@Component
public class CarC {
}
configuration类:
package com.supper.javaconfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author yutao
* @since 2020/4/13 4:17 下午
*/
@Configuration // 表示这个Java类充当xml配置文件
@ComponentScan("com.supper.javaconfig") // 相当于XML中的标签
public class AppConfig {
}
Test类:
package com.supper;
import com.supper.javaconfig.AppConfig;
import com.supper.javaconfig.PersonC;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author yutao
* @since 2020/4/13 4:16 下午
*/
public class ConfigTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
PersonC personC = (PersonC) applicationContext.getBean("personC");
System.out.println(personC);
System.out.println(personC.getCarC());
}
}
之后显示,PersonC
中的CarC
注入成功。
PersonC{carC=com.supper.javaconfig.CarC@7494f96a}
com.supper.javaconfig.CarC@7494f96a
① 我没有提供相关的setter方法和构造方法,spring是怎么注入进去的?
② 就是提供了CarC
的setter方法,spring也不会调用它来进行注入。
带着这样的疑问,只能去源码里找答案了。
首先我们找到AbstractAutowireCapableBeanFactory
这个类,因为@Autewired
的注解解析会调用里面的:
@Override
public void autowireBean(Object existingBean) {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), getBeanClassLoader());
BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw);
populateBean(bd.getBeanClass().getName(), bd, bw);
}
在找到populateBean(bd.getBeanClass().getName(), bd, bw);
,进一步往下看:
这个方法很长,我就贴出部分代码:
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);
}
}
看到pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
这段代码,然后发现其有很多类重载了:
我们看到: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;
}
再看到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);
}
}
}
发现element.inject(target, beanName, pvs);
这段代码也有很多类重载了:
选择:AutowiredAnnotationBeanPostProcessor
类
@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);
}
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);
}
}
}
最后看到field.set(bean, value);
这段代码。
也就是明白了,为什么不提供setter
方法和构造方法也能注入成功。
ReflectionUtils.makeAccessible(field);
这段代码是把访问权限限制解开了,
所以即使我们类设置了private
访问权限,反射照样可以获取得字段属性。
@Autowired
注解 ,spring
利用反射获取到Filed
对象,利用Filed
的set
方法来对字段进行注入赋值。