第四十七讲-Autowired注入底层

第四十七讲-Autowired注入底层

本讲我们来讲一下@Autowired注入底层

我们都知道@Autowired注入是按照类型来进行装配(注入)的,它要支持各种各样的类型,这就决定了@Autowired的实现非常的复杂。

我们来看一个例子:

@Configuration
public class A47_1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_1.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
    }

    static class Bean1 {

        @Autowired
        private Bean2 bean2;

        @Autowired
        public void setBean2(@Lazy Bean2 bean2) {
            this.bean2 = bean2;
        }

        @Autowired
        private Optional<Bean2> bean3;

        @Autowired
        private ObjectFactory<Bean2> bean4;
    }

    @Component("bean2")
    static class Bean2 {
        @Override
        public String toString() {
            return super.toString();
        }
    }
}

1. 根据成员变量的类型注入

// 1. 根据成员变量的类型注入
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"),false);
System.out.println(beanFactory.doResolveDependency(dd1, "bean1", null, null));

运行结果如下:

com.cherry.springa47.A47_1$Bean2@7671cb68

根据成员变量的类型注入(装配)成功

2. 根据方法参数的类型注入

// 2. 根据参数的类型注入
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2,0),false);
System.out.println(beanFactory.doResolveDependency(dd2, "bean1", null, null));

运行结果如下:

com.cherry.springa47.A47_1$Bean2@7671cb68

根据方法参数的类型注入(装配)成功

3. 结果包装类为Optional<Bean2>

有时候@Autowired注入后的类型为包装后的类型,例如下面的代码:

// 3. 结果包装类为Optional\<Bean2>
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
if (dd3.getDependencyType() == Optional.class){
    System.out.println(dd3.getDependencyType());
    dd3.increaseNestingLevel(); // 增加一层内嵌,找到optional中内嵌的类型,也就是泛型的类型
    System.out.println(dd3.getDependencyType());
    Object result = beanFactory.doResolveDependency(dd3, "bean1", null, null);
    Optional.ofNullable(result);
    System.out.println(result);
}

运行结果如下:

class java.util.Optional
class com.cherry.springa47.A47_1$Bean2
com.cherry.springa47.A47_1$Bean2@7671cb68

根据包装类的内部类类型注入(装配)成功

4. 结果包装为ObjectProvider,ObjectFactory

其实这和上面的Optional类型差不多了,具体代码看下面的例子:

// 4. 结果包装为ObjectProvider,ObjectFactory
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
if (dd4.getDependencyType() == ObjectFactory.class){
    dd4.increaseNestingLevel();
    // 将bean工厂注入给成成员变量bean4,当bean4调用getObject()方法才会创建Bean2对象的创建,也就是说推迟了Bean2对象的创建
    ObjectFactory objectFactory = new ObjectFactory() {
        @Override
        public Object getObject() throws BeansException {
            return beanFactory.doResolveDependency(dd4, "bean1", null, null);
        }
    };
    System.out.println(objectFactory.getObject());
}

运行结果如下:

com.cherry.springa47.A47_1$Bean2@7671cb68

我们发现,也正确获得了Bean2对象

5. 对@Lazy的处理

@Lazy注解既可以加在成员变量上,也可以加在方法参数上,作用就是创建一个代理对象,将来访问代理对象的方法时才会获取真实的对象,其作用和ObjectFactory类似,推迟对代理对象的获取。

如下面的代码,我们将bean成员变量加上@Lazy注解:

static class Bean1 {
    @Autowired
    @Lazy
    private Bean2 bean2;
	
    //......
}
// 对@Lazy的处理
DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
// 解析@Autowired和@Lazy注解
// 如果成员变量或方法参数上加上了@Lazy注解,该解析器就会帮助我们创建一个代理对象
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
//检查成员变量或方法上有没有@Lazy注解,如果有,则会帮我们创建出代理类对象
Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
System.out.println(proxy);
System.out.println(proxy.getClass());
}

运行结果如下:

com.cherry.springa47.A47_1$Bean2@6b8ca3c8
class com.cherry.springa47.A47_1$Bean2$$SpringCGLIB$$0
@SuppressWarnings("all")
@Configuration
public class A47_2 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_2.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. 数组类型");
        testArray(beanFactory);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. List 类型");
        testList(beanFactory);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. applicationContext");
        testApplicationContext(beanFactory);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4. 泛型");
        testGeneric(beanFactory);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 5. @Qualifier");
        testQualifier(beanFactory);
        /*
            学到了什么
                1. 如何获取数组元素类型
                2. Spring 如何获取泛型中的类型
                3. 特殊对象的处理, 如 ApplicationContext, 并注意 Map 取值时的类型匹配问题 (另见  TestMap)
                4. 谁来进行泛型匹配 (另见 TestGeneric)
                5. 谁来处理 @Qualifier
                6. 刚开始都只是按名字处理, 等候选者确定了, 才会创建实例
         */
    }
    
    
	// @Qualifier注解:根据bean的名字进行匹配并注入注入(装饰)bean
    private static void testQualifier(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);
        Class<?> type = dd5.getDependencyType();
        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
            BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
            //  @Qualifier("service2")
            if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,name), dd5)) {
                System.out.println(name);
                System.out.println(dd5.resolveCandidate(name, type, beanFactory));
            }
        }
    }
    
    // Dao接口中的泛型Bean对象
    private static void testGeneric(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);
        Class<?> type = dd4.getDependencyType();
        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
            BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
            // 对比 BeanDefinition 与 DependencyDescriptor 的泛型是否匹配
            if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,name), dd4)) {
                System.out.println(name);
                System.out.println(dd4.resolveCandidate(name, type, beanFactory));
            }
        }
    }
    
    // ConfigurableApplicationContext 存储bean对象
    private static void testApplicationContext(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException, IllegalAccessException {
        DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);

        Field resolvableDependencies = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");
        resolvableDependencies.setAccessible(true);
        Map<Class<?>, Object> dependencies = (Map<Class<?>, Object>) resolvableDependencies.get(beanFactory);
//        dependencies.forEach((k, v) -> {
//            System.out.println("key:" + k + " value: " + v);
//        });
        for (Map.Entry<Class<?>, Object> entry : dependencies.entrySet()) {
            // 左边类型                      右边类型
            if (entry.getKey().isAssignableFrom(dd3.getDependencyType())) {
                System.out.println(entry.getValue());
                break;
            }
        }
    }
    
    // 使用List集合存储bean对象
    private static void testList(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
        // 是否List集合类型
        if (dd2.getDependencyType() == List.class) {
            // 获取集合中的元素类型
            Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
            System.out.println(resolve);
            List<Object> list = new ArrayList<>();
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
            for (String name : names) {
                Object bean = dd2.resolveCandidate(name, resolve, beanFactory);
                list.add(bean);
            }
            System.out.println(list);
        }
    }
    
    // 使用数组存储bean对象
    private static void testArray(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);
        // 判断拿到的是不是数组类型
        if (dd1.getDependencyType().isArray()) {
            // 拿到数组中的元素类型
            Class<?> componentType = dd1.getDependencyType().getComponentType();
            System.out.println(componentType);
            // 查找当前容器与所有祖先bean的名字
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);
            List<Object> beans = new ArrayList<>();
            for (String name : names) {
                // 同样根据bean name 找到bean
                System.out.println(name);
                // 根据bean的名字找到bean对象
                Object bean = dd1.resolveCandidate(name, componentType, beanFactory);
                beans.add(bean);
            }
            Object array = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
            System.out.println(array);
        }
    }
    static class Target {
        @Autowired private Service[] serviceArray;
        @Autowired private List<Service> serviceList;
        @Autowired private ConfigurableApplicationContext applicationContext;
        @Autowired private Dao<Teacher> dao;
        @Autowired @Qualifier("service2") private Service service;
    }
    interface Dao<T> {

    }
    @Component("dao1") static class Dao1 implements Dao<Student> { }
    @Component("dao2") static class Dao2 implements Dao<Teacher> { }

    static class Student { }

    static class Teacher { }

    interface Service { }

    @Component("service1")
    static class Service1 implements Service { }

    @Component("service2")
    static class Service2 implements Service { }

    @Component("service3")
    static class Service3 implements Service { }
}

运行结果如下:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. 数组类型
interface com.cherry.springa47.A47_2$Service
service3
service2
service1
[Lcom.cherry.springa47.A47_2$Service;@41e1e210
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. List 类型
interface com.cherry.springa47.A47_2$Service
[com.cherry.springa47.A47_2$Service3@15bbf42f, com.cherry.springa47.A47_2$Service2@550ee7e5, com.cherry.springa47.A47_2$Service1@5f9b2141]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. applicationContext
org.springframework.beans.factory.support.DefaultListableBeanFactory@7fc229ab: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,a47_2,service3,service2,service1,dao2,dao1]; root of factory hierarchy
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4. 泛型
dao2
com.cherry.springa47.A47_2$Dao2@7ea9e1e2
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 5. @Qualifier
service2
com.cherry.springa47.A47_2$Service2@550ee7e5
package com.cherry.springa47;

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Configuration
public class A47_3 {
    public static void main(String[] args) throws NoSuchFieldException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_3.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
        testPrimary(beanFactory);
        testDefault(beanFactory);

        /*
            学到了什么
                1. @Primary 的处理, 其中 @Primary 会在 @Bean 解析或组件扫描时被解析 (另见 TestPrimary)
                2. 最后的防线, 通过属性或参数名匹配
         */
    }

    private static void testDefault(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        DependencyDescriptor dd = new DependencyDescriptor(Target2.class.getDeclaredField("service3"), false);
        Class<?> type = dd.getDependencyType();
        for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
            if(name.equals(dd.getDependencyName())) {
                System.out.println(name);
            }
        }
    }

    private static void testPrimary(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
        DependencyDescriptor dd = new DependencyDescriptor(Target1.class.getDeclaredField("service"), false);
        Class<?> type = dd.getDependencyType();
        for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
            // 判断类上是否加了@Primary注解,如果加了,打印出该bean的名字
            if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
                System.out.println(name);
            }	
        }
    }

    static class Target1 {
        @Autowired private Service service;
    }

    
    // 如果既不加@Primary注解,也不加@Qualified注解,那么Spring还有最后一道防线,就是根据成员变量的名字与bean的名字来进行匹配!!!	
    // 如果匹配的上,则会优先选择匹配上的名字的bean装配(注入)
    static class Target2 {
        @Autowired private Service service3;
    }

    /**
     * @Primary注解相比于@Qualifier注解优先级较低,也能解决@Qualifier解决的问题
     * @Qualifier注解用于解决当依赖项(注入点)存在多个候选bean时的二义性问题。
     * 当你有两个或更多的bean可以满足同一个依赖关系时,@Qualifier可以帮助指定应该使用哪一个bean。
     *
     */
    
    interface Service { }
    @Component("service1") static class Service1 implements Service { }
    @Component("service2") @Primary static class Service2 implements Service { }
    @Component("service3") static class Service3 implements Service { }
}
posted @   LilyFlower  阅读(3)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示