美文网首页
Spring IoC 注入方式探究

Spring IoC 注入方式探究

作者: 苏wisdom | 来源:发表于2020-05-04 13:43 被阅读0次

    1 先说问题

    Spring IoC有哪几种注入方式?

    网上的资料真的很多,但也真啥样的都有,我也不保证自己说的全部都是对的,但是提供一种思考的角度也是好的,望斧正。

    在犹豫不决的时刻,是时候祭出官方文档和源码啦!带着问题看文档和源码,才能真正吃透一个知识点。

    2 配置方式

    首先IoC的容器配置方式主要分为两种:

    1. XML配置 - XML-based configuration
    2. 注解配置 - Annotation-based Container Configuration

    配置方式只是我们使用的时候,告诉Spring去哪找资源而已,并不是所谓的“IoC注入方式”。去看文档,在Annotation-based Container Configuration章节,开篇就对比两种配置方式的优劣。

    image.png

    翻译过来,简单点说,就是Spring对两种方式都可以容纳,不是说一个项目里非此即彼,只能使用其中一种。注释方式在用起来更短、更简洁,但是让人觉得配置分散;XML擅长在不接触源代码或不重新编译它们的情况下连接组件。

    注意:注释注入会在XML注入之前执行。因此,如果同一个类的依赖通过两种方法都配置了注入,XML配置会覆盖注释配置的。

    3 注入方式

    注入方式我们可以说有以下四种,但实际上XML配置方式只实现前两种,后面两种用注解实现去做更方便。

    • 构造器注入
    • setter注入
    • field注入
    • 自定义的方法注入
      传说还有一种接口注入的方式,但是在官方文档上已经找不到踪迹了。

    3.1 构造器注入

    Constructor-based Dependency Injection, 这是官方最推崇的注入方式,也是最便于进行单元测试的方式。但是当构造器中的参数过多,就显得很难受了,要考虑重构。

    3.1.1 XML 配置的构造器注入

    package x.y;
    public class SimpleMovieLister {
    
        // SimpleMovieLister 依赖于 MovieFinder
        private MovieFinder movieFinder;
    
        // 提供给 Spring container 注入 MovieFinder 的构造器
        public SimpleMovieLister(MovieFinder movieFinder) {
            this.movieFinder = movieFinder;
        }
    
        // 省略其他业务逻辑
    }
    

    xml配置的时候大概长这样,在xml里, ref 标签表示你想要向一个对象传递一个引用。

    <beans>
        <bean id="simpleMovieLister" class="x.y.SimpleMovieLister">
            <constructor-arg ref="movieFinder"/>
        </bean>
    
        <bean id="movieFinder" class="x.y.MovieFinder"/>
    </beans>
    

    3.1.2 注解配置的构造器注入

    注解我们就拿@Autowire来举例,其实还可以使用@Resource@Inject等注解。@Autowire注解写在构造方法上,是在doCreateBean方法中的createBeanInstance时候注入的。

    @Service
    public class MovieRecommenderService {
    
        private final CustomerPreferenceDao customerPreferenceDao;
    
        @Autowired
        public MovieRecommenderService(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
    
        // ...
    }
    

    MovieRecommenderService 类一般情况下我们都会在类名上写@Service交由容器作为单例储存起来,不用自己去XML里费劲写<bean>了。
    非SpringBoot项目还需要在XML配置文件中使用<context:annotation-config/>标签开启自动注解。

    3.2 Setter注入

    3.2.1 XML配置的Setter注入

    package x.y;
    public class SimpleMovieLister {
    
        // SimpleMovieLister 依赖于 MovieFinder
        private MovieFinder movieFinder;
    
        // 提供给容器进行注入的 setter 方法
        public void setMovieFinder(MovieFinder movieFinder) {
            this.movieFinder = movieFinder;
        }
    
        // 其他业务逻辑
    }
    

    xml的配置大概长这样

       <bean id="simpleMovieLister" class="x.y.SimpleMovieLister">
          <property name="movieFinder" ref="movieFinder"/>
       </bean>
    
       <bean id="movieFinder" class="x.y.MovieFinder">
       </bean>
    

    3.2.2 注解配置的Setter注入

    @Autowired放在Setter方法上时,是装配属性的时候才注入,即调用doCreateBean方法中的populateBean

    public class SimpleMovieLister {
    
        private MovieFinder movieFinder;
    
        @Autowired
        public void setMovieFinder(MovieFinder movieFinder) {
            this.movieFinder = movieFinder;
        }
    
        // ...
    }
    

    3.3 Field注入

    这里进行Field与构造函数混合注入,事实上我们看到很多的项目,都是只使用的Field注入,这样做的问题在于,单元测试的时候想要注入Mock的依赖就很麻烦。

    @Autowired放在Field上时,是装配属性的时候才注入,即调用doCreateBean方法中的populateBean

    public class MovieRecommender {
    
        private final CustomerPreferenceDao customerPreferenceDao;
    
        @Autowired
        private MovieCatalog movieCatalog;
    
        @Autowired
        public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
    
        // ...
    }
    

    3.4 自定义的方法注入

    emmm...暂时还没见过哪个项目里是这么写的

    如果@Autowire写在自定义的方法上,也是装配属性的时候才注入,doCreateBean方法中的populateBean

    public class MovieRecommender {
    
        private MovieCatalog movieCatalog;
    
        private CustomerPreferenceDao customerPreferenceDao;
    
        @Autowired
        public void prepare(MovieCatalog movieCatalog,
                CustomerPreferenceDao customerPreferenceDao) {
            this.movieCatalog = movieCatalog;
            this.customerPreferenceDao = customerPreferenceDao;
        }
    
        // ...
    }
    

    相关文章

      网友评论

          本文标题:Spring IoC 注入方式探究

          本文链接:https://www.haomeiwen.com/subject/ycieghtx.html