Spring之依赖注入环节之@Autowired
注入模型下为什么可以给set属性来进行赋值
1、预备知识点:java属性描述器
首先来介绍一下java中的属性描述器。
首先来介绍一下什么叫做javabean?java认为一个bean中的属性是用private关键字修饰的,然后对其提供对应的getter/setter方法
如UserInfo类:
public class UserInfo {
private long userId;
private String userName;
private int age;
private String emailAddress;
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
在类UserInfo中有属性userName,那我们可以通过getUserName, setUserName来得到其值或者设置新的值。通过getUserName/setUserName来访问userName属性,这就是默认的规则。Java JDK中提供了一套API用来访问某个属性的getter/setter方法,这就是内省。
PropertyDescriptor类:(属性描述器)
PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:
1. getPropertyType(),获得属性的Class对象;
2. getReadMethod(),获得用于读取属性值的方法;
3. getWriteMethod(),获得用于写入属性值的方法;
4. hashCode(),获取对象的哈希值;
5. setReadMethod(Method readMethod),设置用于读取属性值的方法;
6. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。
示例代码:
public class Test {
public static void main(String[] args) throws Exception {
UserInfo userInfo = new UserInfo();
// 加入说我现在已经知道了这个类中的属性
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("userId", UserInfo.class);
// 得到这个属性的get方法
Method readMethod = propertyDescriptor.getReadMethod();
// 得到这个属性的write方法
Method writeMethod = propertyDescriptor.getWriteMethod();
// 现在我想获取得到这个属性的值:
Object invoke = readMethod.invoke(userInfo);
System.out.println("通过getUserId来获取得到userId的值------->"+invoke); // 0为默认值
// 通过set方法来对其设置一个值
writeMethod.invoke(userInfo, 666);
invoke = readMethod.invoke(userInfo);
System.out.println("通过getUserId来获取得到userId的值------->"+invoke); // 0为默认值
}
}
java认为作为一个javabean,应该有对应的private修饰的属性,private修饰的属性应该有对应的setter/getter方法。
那么java可以从Javabean来做一个推断,如果有private修饰的属性,那么就存在对应的setter/getter方法;
如果有对应的setter/getter方法,那么就应该存在着对应的属性。
所以spring中也利用了这个特性来做了一些处理。
举个例子:
public class UserInfo{
private Integer age;
public void setAge111(Integer age){
this.age = age;
}
}
如果说通过属性描述器来进行描述方法setAge111的话,那么java认为属性应该有一个叫age111的属性,但是实际上我们写的却是age.
这也是初学java对象的时候,java中的命名方式。
2、spring利用Javabean特性做事情
@Component
public class OrderService {}
正常的话,如果是没有添加任何注解的时候,这个类是不会成为Spring容器中的Bean的。
public class UserService {
private OrderService orderService;
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void test(){
System.out.println("---------->"+orderService);
}
}
在配置类中来配置,让UserService中的属性按照注入模型来进行注入。
也就是说UserService中的属性必须要提供对应的set方法,spring容器能够帮其从容器中来找到对应的需要的Bean的Name来进行注入。
@Configuration
@ComponentScan("com.guang.beandefinitaiontest.demo12")
public class AppConfig {
@Bean(autowire= Autowire.BY_NAME)
public UserService userService(){
return new UserService();
}
}
测试类:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.test();
}
}
控制台输出:
---------->com.guang.beandefinitaiontest.demo12.service.OrderService@fdefd3f
那么原理在哪里?如何来分析?
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean中
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
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;
}
对于UserService来说,对应的AutowireMode就是BY_NAME,那么肯定对应到这里来。
那么来看下是如何来进行处理的。
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
}
else {
}
}
}
在第一行代码中,会获取得到当前类的所有的get和set方法
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
PropertyValues pvs = mbd.getPropertyValues();
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
但是如上所示,对于一个属性来说,必须要有set方法才会添加到result中来,然后将set方法来进行返回。
对于每个类来说,都有一个getClass方法,因为这里是Object类的方法,而这个对应的get方法,但是当前对象中可能没有class属性。
所以这里是来做了一个过滤。
问题一:为何要有这样的一个判断?
这里注意有几个判断:
如:BeanUtils.isSimpleProperty(pd.getPropertyType(),判断是否是简单类型
public static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
如果说是简单类型,那么这里不会来进行注入。只有复杂类型才会来进行注入。
但是对于@Autowired来说,@Autowired是可以来进行注入的。
来做一个实验:
public class UserService {
private OrderService orderService;
private Date date;
public void setDate(Date date) {
this.date = date;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void test(){
System.out.println("---------->"+orderService);
System.out.println("---------->"+date);
}
}
@Configuration
@ComponentScan("com.guang.beandefinitaiontest.demo12")
public class AppConfig {
@Bean
public Date date(){
return new Date();
}
@Bean(autowire= Autowire.BY_NAME)
public UserService userService(){
return new UserService();
}
}
然后打印测试:
---------->com.guang.beandefinitaiontest.demo12.service.OrderService@a4102b8
---------->null
说明了使用注入模型的时候,简单类型是不会来进行注入的。
再比如:
!pvs.contains(pd.getName()
也就是说程序员如果对某个属性来进行了设置,那么这里来跳过。不会从容器中来给这个set方法对应的属性再来进行赋值了。
那么我来写个案例测试一下:
public class Person {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void test(){
System.out.println("Person对应的test的值是:"+userService);
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(Person.class);
genericBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
UserService userService1 = new UserService();
System.out.println("自动注入的userService的值是:"+userService1);
genericBeanDefinition.getPropertyValues().add("userService",userService1);
context.registerBeanDefinition("person",genericBeanDefinition);
context.refresh();
UserService userService = context.getBean(UserService.class);
userService.test();
System.out.println("容易中的userService的值是:"+userService);
Person person = context.getBean(Person.class);
person.test();
}
}
手动的来对Person中的userService属性来进行注入,那么对于Person来说,就不需要来从容器中来进行查找得到对应的值了。
控制台输出:
自动注入的userService的值是:com.guang.beandefinitaiontest.demo12.service.UserService@26f67b76
---------->com.guang.beandefinitaiontest.demo12.service.OrderService@69930714
---------->null
容易中的userService的值是:com.guang.beandefinitaiontest.demo12.service.UserService@7a52f2a2
Person对应的test的值是:com.guang.beandefinitaiontest.demo12.service.UserService@26f67b76
但是一旦我将一些代码注释掉:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(Person.class);
genericBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
/* UserService userService1 = new UserService();
System.out.println("自动注入的userService的值是:"+userService1);
genericBeanDefinition.getPropertyValues().add("userService",userService1);*/
context.registerBeanDefinition("person",genericBeanDefinition);
context.refresh();
UserService userService = context.getBean(UserService.class);
userService.test();
System.out.println("容易中的userService的值是:"+userService);
Person person = context.getBean(Person.class);
person.test();
}
}
控制台打印:
---------->com.guang.beandefinitaiontest.demo12.service.OrderService@11dc3715
---------->null
容易中的userService的值是:com.guang.beandefinitaiontest.demo12.service.UserService@69930714
Person对应的test的值是:com.guang.beandefinitaiontest.demo12.service.UserService@69930714
那么就会是一样的。
然后对set方法对应的属性来进行赋值:
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
}
else {
}
}
再次看到了熟悉的getBean方法,这里就是根据属性名称去容器中去查找,如果bean存在,就添加一下,然后注册
问题二:为什么这里找到了之后没有直接进行赋值?
其实对于@Autowired和@Resource来说,是直接来进行赋值的。但是这里没有来进行赋值。
但是中间是spring来进行依赖注入的点,是对@Autowired和@Resource注解来做处理的!
所以我觉得这里可能是要放置spring在进行@Autowired和@Resource的时候,放置破坏被注入了里面的值。
而保持让spring自己来注入的,后续会写个测试用例来测试一下。
最终是在哪里来进行赋值的呢?
是在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
中的最后一行代码中来进行赋值的:
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
Spring中的依赖注入
spring中的依赖注入使用注解的话,大概是有两个注解。@Autowird和@Resource这两个。
那么分别来看一下,这两个注解都是如何来发挥作用的。
Spring内置处理器
因为在后面需要使用到来对@Autowired注解和@Resource注解做处理,Spring提前内置了处理器来进行处理。
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)中
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
然后在org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors中来实例化Bean,对应的步骤在org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
Spring统一处理
无论是对于@Autowird和@Resource来说,这两个注解都是可以作用在类中的方法和属性上面的。
Spring在创建BeanDefinition对应的示例之后,开始来对进行属性填充:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
在这个地方,会有AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor,这两个后置处理器来进行处理。
下面分别在下面来进行说明:
@Autowired
对于org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition来说,看下这里的逻辑:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
首先来查找得到@Autowired的元信息。看看如何查找的?
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable 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);
}
// 解析注入点并缓存
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
上来先从缓存中来查找,没有的话;再去查询:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 如果一个Bean的类型是String...,那么则根本不需要进行依赖注入
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<>();
// 遍历targetClass中的所有Field
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// field上是否存在@Autowired、@Value、@Inject中的其中一个
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// static filed不是注入点,不会进行自动注入
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 构造注入点
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 遍历targetClass中的所有Method
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// method上是否存在@Autowired、@Value、@Inject中的其中一个
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// static method不是注入点,不会进行自动注入
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
// set方法最好有入参
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("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);
return InjectionMetadata.forElements(elements, clazz);
}
在这里来划分步骤:
首先判断,什么类型是不需要来进行注入的:
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
而这里的autowiredAnnotationTypes中的值是,@Autowired,@Value注解的
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
也就是说,如果类上、字段上和方法上都没有@Autowired,@Value注解,那么将不会来进行注入。也就是下面的环节将不会进来。
然后上面来遍历所有的属性和方法
遍历属性
// 遍历targetClass中的所有Field
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// field上是否存在@Autowired、@Value、@Inject中的其中一个
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// static filed不是注入点,不会进行自动注入
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 构造注入点
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
遍历方法
// 遍历targetClass中的所有Method
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// method上是否存在@Autowired、@Value、@Inject中的其中一个
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// static method不是注入点,不会进行自动注入
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
// set方法最好有入参
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("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));
}
});
对于属性来说,添加的是AutowiredFieldElement,对于字段来说,添加的是AutowiredMethodElement。
从这里来看的话,最终都会保存到elements集合中来,而elements集合中的每个元素是InjectionMetadata.InjectedElement类型。
那么来看一下类结构发现:AutowiredMethodElement和AutowiredFieldElement都是继承自InjectedElement的。
public abstract static class InjectedElement {
protected final Member member;
protected final boolean isField;
@Nullable
protected final PropertyDescriptor pd;
@Nullable
protected volatile Boolean skip;
}
遍历父类中的属性和方法
然后在外层中加了一个do...while循环
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
那么继续来看一个东西,最终还会来找到父类中的加了@Autowired的属性和方法。
那么来测试一下:
@Component
public class Worker {}
public abstract class AbstractService {
@Autowired
private Worker worker;
public void work(){
System.out.println("worker的值是:"+worker);
}
}
@Component
public class UserService extends AbstractService {
}
@Component
public class OrderService extends AbstractService {
}
写个测试类来进行测试:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean(OrderService.class);
orderService.work();
UserService userService = context.getBean(UserService.class);
userService.work();
}
}
控制台输出:
worker的值是:com.gunag.ioc.demo1.service.Worker@1e643faf
worker的值是:com.gunag.ioc.demo1.service.Worker@1e643faf
注意的地方
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable 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);
}
// 解析注入点并缓存
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
这里是首先来从缓存中来进行查找,如果没有找到;那么真的去查找,查找完成之后,放入到缓存中去。
这样子的设计模式也是为了提高效率。
但是下面有一行代码:
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
for (InjectedElement element : this.injectedElements) {
Member member = element.getMember();
// 将Field或Method记录到BeanDefinition中的externallyManagedConfigMembers中,
// 表示该Field或Method是BeanFactory外部管理的
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
checkedElements.add(element);
}
}
this.checkedElements = checkedElements;
}
这里的checkedElements和injectedElements之间的关系,我并不是特别清楚这里为什么要这样子来做。
依赖注入阶段
既然在postProcessMergedBeanDefinition阶段已经找到了注入点,那么接下来就应该来进行注入了。
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean阶段开始来进行注入:
这次调用的是另外一个后置处理器:InstantiationAwareBeanPostProcessor的postProcessProperties方法
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 找注入点(所有被@Autowired注解了的Field或Method)
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;
}
因为上面已经找到了注入点,然后就直接来进行注入了。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 这里拿到的是checkedElements
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);
}
}
}
这里的注入阶段很简单,直接通过反射来进行操作:
针对AutowiredFieldElement来说:
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
// 对于原型Bean,第一次创建的时候,也找注入点,然后进行注入,此时cached为false,注入完了之后cached为true
// 第二次创建的时候,先找注入点(此时会拿到缓存好的注入点),也就是AutowiredFieldElement对象,此时cache为true,也就 // 进到此处了
// 注入点内并没有缓存被注入的具体Bean对象,而是beanName,这样就能保证注入到不同的原型Bean对象
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 根据filed从BeanFactory中查到的匹配的Bean对象
value = resolveFieldValue(field, bean, beanName);
}
// 反射给filed赋值
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
针对AutowiredMethodElement来说:
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 如果pvs中已经有当前注入点的值了,则跳过注入
if (checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
try {
arguments = resolveCachedArguments(beanName);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
arguments = resolveMethodArguments(method, bean, beanName);
}
}
else {
arguments = resolveMethodArguments(method, bean, beanName);
}
if (arguments != null) {
try {
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
所以最终来到了最为关键的步骤:
value = resolveFieldValue(field, bean, beanName);
arguments = resolveMethodArguments(method, bean, beanName);
根据方法和字段来从容器中来找到对应的值,最终将会来到:
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
int argumentCount = method.getParameterCount();
Object[] 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();
// 遍历每个方法参数,找到匹配的bean对象
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
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;
}
}
return arguments;
}
那么这里又会有一个关键流程:
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
来到了这个方法:
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 用来获取方法入参名字的
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 所需要的类型是Optional
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// 所需要的的类型是ObjectFactory,或ObjectProvider
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选Bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// descriptor表示某个属性或某个set方法
// requestingBeanName表示正在进行依赖注入的Bean
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
@Lazy的作用
// 在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选Bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
会执行到:
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}
org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#isLazy
protected boolean isLazy(DependencyDescriptor descriptor) {
for (Annotation ann : descriptor.getAnnotations()) {
Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
if (lazy != null && lazy.value()) {
return true;
}
}
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
if (lazy != null && lazy.value()) {
return true;
}
}
}
return false;
}
在这个阶段中,会来判断字段或者是方法有没有添加@Lazy注解。
如果添加了@Lazy注解,那么将会来创建一个代理对象:
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
BeanFactory beanFactory = getBeanFactory();
Assert.state(beanFactory instanceof DefaultListableBeanFactory,
"BeanFactory needs to be a DefaultListableBeanFactory");
final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return descriptor.getDependencyType();
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() {
Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
if (target == null) {
Class<?> type = getTargetClass();
if (Map.class == type) {
return Collections.emptyMap();
}
else if (List.class == type) {
return Collections.emptyList();
}
else if (Set.class == type || Collection.class == type) {
return Collections.emptySet();
}
throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
"Optional dependency not present for lazy injection point");
}
if (autowiredBeanNames != null) {
for (String autowiredBeanName : autowiredBeanNames) {
if (dlbf.containsBean(autowiredBeanName)) {
dlbf.registerDependentBean(autowiredBeanName, beanName);
}
}
}
return target;
}
@Override
public void releaseTarget(Object target) {
}
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
return pf.getProxy(dlbf.getBeanClassLoader());
}
而当这个代理真正执行的时候,则会来执行getTarget方法,从容器中来获取得到容器中的对象。
举个例子说明一下:
@Component
public class Worker {}
@Component
public class OrderService extends AbstractService {
@Autowired
@Lazy
private Worker worker;
public void test(){
worker.test();
}
}
这里就相当于是在属性worker注入的时候,这里先赋值一个代理的对象;而当worker在调用test方法的时候,则是会去容器中找到真正的对应的Worker对象来调用。也就是对应的是上面的逻辑。
方法参数也是可以的。
这里也体现出来了延迟加载的一个作用。
最后一步
所以这里就是重点逻辑了。正常来说都是走最后一步路程:
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
所以来看一下具体的详细的代码:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 获取得到字段或者是方法上的类型
Class<?> type = descriptor.getDependencyType();
// 获取@Value所指定的值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 占位符填充(${})
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 解析Spring表达式(#{})
value = evaluateBeanDefinitionString(strVal, bd);
}
// 将value转化为descriptor所对应的类型
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 如果descriptor所对应的类型是数组、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步做筛选了
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// required为true,抛异常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 记录匹配过的beanName
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
@Value
其实对于@Value来说,最终需要从Envirement对象中取出来。可以有yml配置文件、JVM参数形式取出、properties文件取出。
但是取出来对应的值之后,需要利用类型转换器转换到对应的类型中去。
比如我们常常在配置文件中配置:
name:
lig
只需要在@Value("${name}"),那么利用解析器可以拿到lig这个值。但是因为@Value可能是加载注解上的。
所以这个时候需要利用到类型转换器来发挥作用,也就是说进行类型转换。
所以这个时候,可能会出现ClassCastException异常。
这里也就是类型转换器的作用!非常有用,工具类要利用好。
甚至有的类型转换器可以将json转换成对象。
@Value("#{lig}"):如果这样子来写的话,表示的是去容器中找一个name为lig的bean来注入到当前bean中来。
所以这也是一种属性注入的方式。
// 将value转化为descriptor所对应的类型
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
如果@Autowired作用对象是Map或者是List或者数组
// 如果descriptor所对应的类型是数组、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步做筛选了
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
// 不为空就直接返回
return multipleBeans;
}
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
if (descriptor instanceof StreamDependencyDescriptor) {
// 找到type所匹配的所有bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// 构造成一个stream
Stream<Object> stream = matchingBeans.keySet().stream()
.map(name -> descriptor.resolveCandidate(name, type, this))
.filter(bean -> !(bean instanceof NullBean));
// 排序
if (((StreamDependencyDescriptor) descriptor).isOrdered()) {
stream = stream.sorted(adaptOrderComparator(matchingBeans));
}
return stream;
}
else if (type.isArray()) {
// 得到数组元素的类型
Class<?> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class<?> resolvedArrayType = resolvableType.resolve(type);
if (resolvedArrayType != type) {
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
// 根据数组元素类型找到所匹配的所有Bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// 进行类型转化
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
if (result instanceof Object[]) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
Arrays.sort((Object[]) result, comparator);
}
}
return result;
}
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (result instanceof List) {
if (((List<?>) result).size() > 1) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
((List<?>) result).sort(comparator);
}
}
}
return result;
}
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
// 如果Map的key不是String
if (String.class != keyType) {
return null;
}
Class<?> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
return null;
}
}
可以看到这里还是支持这种集合形式的。
正常是单个的情况
使用@Autowired注解来找的时候,首先通过类型来查找
// 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// required为true,抛异常
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
这里根据类型找到了单个类型的多个bean,那么下面将会来进行判断。
但是如果利用@Autowired注解来进行查找的时候,如果说没有找到,但是@Autowired中的注解属性Required又是默认为true的,找不到这里就会来报错。如果Required为false的话,那么这里就直接返回null
然后接着来判断:
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 不是多个,又不为空,那么肯定就只有一个
// 确定只有一个匹配
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
@Autowired根据类型匹配找到多个,又该如何处理
if (matchingBeans.size() > 1) {
// 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
那么看一下重要方法:
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
// candidates表示根据类型所找到的多个Bean,判断这些Bean中是否有一个是@Primary的
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
// 取优先级最高的Bean
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// Fallback
// 匹配descriptor的名字,要么是字段的名字,要么是set方法入参的名字
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
// resolvableDependencies记录了某个类型对应某个Bean,启动Spring时会进行设置,比如BeanFactory.class对应 // BeanFactory实例
// 注意:如果是Spring自己的byType,descriptor.getDependencyName()将返回空,只有是@Autowired才会方法属性名或方法 // 参数名
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
return null;
}
第一个判断,根据类型找到多个bean的时候,优先找加了@Primary注解的bean。
// candidates表示根据类型所找到的多个Bean,判断这些Bean中是否有一个是@Primary的
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String primaryBeanName = null;
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
// 如果有多个@primary,这里报错
if (candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " + candidates.keySet());
}
else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
}
else {
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}
第二个判断,判断是否在类上加了@Priority注解
// 取优先级最高的Bean
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
看下具体实现:
protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String highestPriorityBeanName = null;
Integer highestPriority = null;
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (beanInstance != null) {
Integer candidatePriority = getPriority(beanInstance);
if (candidatePriority != null) {
if (highestPriorityBeanName != null) {
if (candidatePriority.equals(highestPriority)) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"Multiple beans found with the same priority ('" + highestPriority +
"') among candidates: " + candidates.keySet());
}
else if (candidatePriority < highestPriority) {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
}
}
else {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
}
}
}
}
return highestPriorityBeanName;
}
如果有多个类型的Bean,需要调整一下优先级。不然优先级如果相同,那么会报错。
在@Priority中的数字越小,优先级越高。
第三个判断,根据bean的名称来进行判断
// Fallback
// 匹配descriptor的名字,要么是字段的名字,要么是set方法入参的名字
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
// resolvableDependencies记录了某个类型对应某个Bean,启动Spring时会进行设置,比如BeanFactory.class对应BeanFactory实 // 例
// 注意:如果是Spring自己的byType,descriptor.getDependencyName()将返回空,只有是@Autowired才会方法属性名或方法参数名
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
如果没有加@Primary和@Priority,才会根据名字来进行注入。
问题:如果有优先级的存在,那么优先级比较低的如何处理?
如上面所示,如果一个类有两个Bean,如A和B,但是因为A的优先级比较高,B的优先级比较低。
那么在注入的时候都是使用的是A,那么B可能在当前注入阶段中使用不到。所以又该如何来进行处理?
spring中的处理很智能:
// 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
如果说,当前根据类型查找出来的(BeanDefinition中的beanClass),如果类型是Class类型的,那么表示还没有进行bean的生命周期;
那么在这里,将会来走bean的生命周期;如果对应的是null,还要判断required是否为true,如果为true,但是返回的是null,那么直接报错;如果required是FALSE,那么这里最终返回的是null。
注入完成之后,直接将最终的进行返回。
根据类型找到所有的Bean的原理
这里是一个核心方法
// 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
首先应该自己来思考一下,根据类型来找bean的话,可以从哪里来找。上面也提到了一种,根据BeanDefinition中的beanclass来查找。
我总结一下:1、单例池;2、BeanDefinition;3、FactoryBean中的getObjectType方法;
那么看看spring是如何来做到的?
// 从BeanFactory中找出和requiredType所匹配的beanName,仅仅是beanName,这些bean不一定经过了实例化,只有到最终确定某个Bean了,如果这个Bean还没有实例化才会真正进行实例化
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
首先根据类型来找到匹配的所有的Bean的名称。看看如何来查找到的
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
// 从本容器中找
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
// 从父容器找并放入result
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
从父子容器中来根据类型查找,如果只需要看一下根据类型来进行查找的方式:
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
// 如果没有冻结,就根据类型去BeanFactory找,如果冻结了,可能就跳过这个if然后去缓存中去拿了
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
// 把当前类型所匹配的beanName缓存起来
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
看一个重要参数:includeNonSingletons,是否包含非单例的。
如果includeNonSingletons为true,那么就会找到所有的Definition;如果为FALSE,那么表示的是只要单例bean;
可以看到有两个对应类型的集合分别来进行存储:allBeanNamesByType和singletonBeanNamesByType
所以来到了核心方法:
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
看下具体实现:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
// 遍历所有的BeanDefinitions
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
// 判断mbd允不允许获取对应类型
// 首先mdb不能是抽象的,然后allowEagerInit为true,则直接去推测mdb的类型,并进行匹配
// 如果allowEagerInit为false,那就继续判断,如果mdb还没有加载类并且是懒加载的并且不允许提前加载类,那mbd不能用来进行匹配(因为不允许提前加载类,只能在此mdb自己去创建bean对象时才能去创建类)
// 如果allowEagerInit为false,并且mbd已经加载类了,或者是非懒加载的,或者允许提前加载类,并且不用必须提前初始化才能获取类型,那么就可以去进行匹配了
// 这个条件有点复杂,但是如果只考虑大部分流程,则可以忽略这个判断,因为allowEagerInit传进来的基本上都是true
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
// 当前BeanDefinition不是FactoryBean,就是普通Bean
if (!isFactoryBean) {
// 在筛选Bean时,如果仅仅只包括单例,但是beanName对应的又不是单例,则忽略
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
...........................
return StringUtils.toStringArray(result);
}
首先来遍历容器中所有的BeanDefinition的名称集合,然后判断是否是factorybean。接下来将会对是factorybean和不是factorybean的BeanDefinition来做处理
首先来一下判断逻辑isTypeMatch:
这里的代码太长,主要还是上面的三种逻辑来进行判断的:单例池、BeanDefinition中的beanClass还有FactoryBean中的getType来进行判断和spring找的类型是否是匹配的。
还有spring内置的几个对应的类型存在resolvableDependencies集合中:
// 根据类型从resolvableDependencies中匹配Bean,resolvableDependencies中存放的是类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
上面只是找到了,找到了之后需要来进行筛选:
筛选一:自己注入自己的情况和不满足注入的情况
for (String candidate : candidateNames) {
// 如果不是自己,则判断该candidate到底能不能用来进行自动注入
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
如果是自己注入自己的情况,并且找到了当前类型的bean,那么会将自己过滤掉,将在外面注入的添加进来result集合中来。
这个不符合自己只是其中的一个条件,还有另外一个条件,用来判断是否能够满足注入。
也就是isAutowireCandidate这个条件,也就是说虽然说配置了,但是不满足依赖注入条件。
如下所示:
/**
* 不会自动注入
* @return
*/
@Bean(autowireCandidate = false)
public OrderService orderService1(){
return new OrderService();
}
@Bean
public OrderService orderService2(){
return new OrderService();
}
public class OrderService implements BeanNameAware {
private String beanBame;
@Override
public void setBeanName(String name) {
beanBame =name;
}
public void name(){
System.out.println(beanBame);
}
}
控制台打印:
orderService3
这里也是一种判断方式。
但是如果将autowireCandidate = false去掉,那么就又会报错了。因为按照类型找到了多个,根据名称找,发现没有匹配的,报错。
判断能够进行注入
我们从上面能够看到,对于isAutowireCandidate这个判断来说,这里也是分为了好几个步骤来进行区分的。
首先调用:
- org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate
- org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver#isAutowireCandidate;
- org.springframework.beans.factory.support.SimpleAutowireCandidateResolver#isAutowireCandidate
分别来介绍一下:
- 1、第一种是用来处理@Qulifier注解的;
- 2、第二种是用来处理泛型的;
- 3、第三种就是根据BeanDefinition中的属性判断的;
如果父类中的判断不满足,那么子类也不满足。所以说优先级顺序是倒置过来的。
但是如果父类的满足了,子类再来判断自己的条件;
刚刚使用注解来添加的就是第三种;第二种泛型的几乎用不上,不需要管;但是第三种是可以采用的;
泛型判断是否能够注入
找到类后,需要循环对每个beanName是否能够来进行注入。
首先判断的是是否能够被依赖注入;
然后判断泛型对应的类能够被找到;
最终通过@Qulified指定的名称来找对应的名称;
下面来看下泛型的。
public class BaseService<O, S> {
@Autowired
O o;
@Autowired
S s;
public void helo(){
System.out.println("o的值是:"+o);
System.out.println("s的值是:"+s);
}
}
@Component
public class OrderService {
}
@Component
public class StockService {
}
public class BaseService<O, S> {
@Autowired
O o;
@Autowired
S s;
public void helo(){
System.out.println("o的值是:"+o);
System.out.println("s的值是:"+s);
}
}
@Component
public class UserService extends BaseService<OrderService,StockService> {
public void test(){
helo();
}
}
测试类:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean(UserService.class).test();
}
}
o的值是:com.gunag.ioc.demo2.service.impl.OrderService@36d64342
s的值是:com.gunag.ioc.demo2.service.impl.StockService@39ba5a14
上面的使用到了泛型,就是org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver#isAutowireCandidate;来进行处理的。
具体的原理是使用了JDK的反射确定泛型的值,从而来确定真正依赖的值是什么。不再来深究这里的原理了,过于底层了。
那么我们看一下@Qualifier能够处理的:
public class OrderService implements BeanNameAware {
private String name;
@Override
public void setBeanName(String name) {
this.name = name;
}
public void test(){
System.out.println("beanName is ---->"+name);
}
}
配置类:
@Configuration
@ComponentScan("com.gunag.ioc.demo2")
public class AppConfig {
@Bean
@Qualifier("o1")
public OrderService orderService1(){
return new OrderService();
}
@Bean
@Qualifier("o2")
public OrderService orderService2(){
return new OrderService();
}
}
服务类:
@Component
public class PersonService {
@Autowired
@Qualifier("o1")
private OrderService orderService;
public void test(){
orderService.test();
}
}
控制台打印:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean(PersonService.class).test();
}
}
在修改@Qualifier("o1")中的值的时候,可以看到控制台显示也是不同的。
// 为空要么是真的没有匹配的,要么是匹配的自己
if (result.isEmpty()) {
// 需要匹配的类型是不是Map、数组之类的
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 匹配的是自己,被自己添加到result中
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
依赖注入缓存阶段
对应的是下面这行代码:
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
这里为什么会有缓存呢?对于一个Bean来说,依赖注入阶段,我们通过理解的是只会来注入一次,这里的缓存难道会存在注入多次的情况来使用到这个缓存吗?
那么这个时候应该想要下面情况呢?
@Component
public class UserService {
@Autowired
private OrderService orderService;
@Autowired
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
首先加了@Autowired的属性和方法是两个注入点,但是并没有使用到缓存。
因为对于字段和方法来说:
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
private final boolean required;
private volatile boolean cached;
}
private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
private final boolean required;
private volatile boolean cached;
}
这是两个cached字段的值,所以这两个的值是不同的。
那么这里的缓存表示的就不是这个意思了。那么观察一下缓存中做了什么事情:
if (this.cached) {
try {
arguments = resolveCachedArguments(beanName);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
arguments = resolveMethodArguments(method, bean, beanName);
}
}
传入的是beanName,而不是真实的bean。所以这就很奇怪。
所以这个时候应该考虑到不是单例bean的问题了,而可能是其他类型的bean,比如说原型bean。
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class OrderService {
}
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class UserService {
@Autowired
private OrderService orderService;
@Autowired
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
测试类:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig13.class);
UserService userService = context.getBean(UserService.class);
UserService userService1 = context.getBean(UserService.class);
}
}
打上断点,发现果然是执行到了这里。第二次调用的时候这里会来走缓存。
这里也发现了spring为什么在注册时候要来设计一下缓存,让原型bean也来走这一步的逻辑!
但是这里也突然想到了,为什么要调用getBean方法,让原型bean来进行实例化了。
走缓存的时候存的时候是利用ShortcutDependencyDescriptor,那么取的时候也需要利用到ShortcutDependencyDescriptor来取。
@Autowired流程图总结
首先在利用@Autowired注解来进行注入的时候,发现了几个关键方法。下面来总结一下对应的流程。
1、beanFactory.resolveDependency
2、findAutowireCandidates
来总结一下这两个方法的流程。因为findAutowireCandidates是在resolveDependency内部的,所以先来总结一下findAutowireCandidates方法。
findAutowireCandidates方法
先按照类型来进行查找beanName,然后根据beanName找到具体的类型:
@Autowired具体的细节流程是: