zoukankan      html  css  js  c++  java
  • 【Spring注解驱动开发】如何实现方法、构造器位置的自动装配?我这样回答让面试官很满意!

    写在前面

    冰河技术 微信公众号前面的文章中,我们介绍了如何使用注解来自动装配Spring组件。之前将的都是在来的字段上添加注解,那有没有什么方法可以实现方法、构造器位置的自动装配吗?今天我们就一起来探讨下如何实现方法、构造器位置的自动装配。

    关注 冰河技术 技术微信公众号,后台回复“spring注解”关键字,领取项目工程源码。

    再谈@Autowired注解

    在我发表在 冰河技术 微信公众号的《【Spring注解驱动开发】使用@Autowired@Qualifier@Primary三大注解自动装配组件,你会了吗?》一文中简单介绍了下@Autowired注解注解的使用方法。下面,我们再来看下@Autowired注解的源码。

    package org.springframework.beans.factory.annotation;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
    	boolean required() default true;
    }
    

    我们通过@Autowired注解的源码可以看出,在@Autowired注解上标注有如下的注解信息。

    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    

    可以看出@Autowired注解不仅可以标注在字段上。也可以标注在构造方法上,实例方法上,参数上。

    项目案例

    案例准备

    接下来,我们在项目中新建一个Dog类,在Doc类中有一个Cat类的引用,并且我们使用@Component注解将Dog类加载到IOC容器中,如下所示。

    package io.mykit.spring.plugins.register.bean;
    import org.springframework.stereotype.Component;
    /**
     * @author binghe
     * @version 1.0.0
     * @description 测试实体类
     */
    @Component
    public class Dog {
    
        private Cat cat;
    
        public Cat getCat() {
            return cat;
        }
    
        public void setCat(Cat cat) {
            this.cat = cat;
        }
    
        @Override
        public String toString() {
            return "Dog{" +  "cat=" + cat + '}';
        }
    }
    

    配置好之后,我们还需要在AutowiredConfig类的@ComponentScan注解中进行配置,使其能够扫描io.mykit.spring.plugins.register.controller包下的类,如下所示。

    @Configuration
    @ComponentScan(value = {
            "io.mykit.spring.plugins.register.dao",
            "io.mykit.spring.plugins.register.service",
            "io.mykit.spring.plugins.register.controller",
            "io.mykit.spring.plugins.register.bean"})
    public class AutowiredConfig {
    }
    

    此时,我们可以直接在Dog类中的cat字段上添加@Autowired注解,使其自动装配。这是我们在《【Spring注解驱动开发】使用@Autowired@Qualifier@Primary三大注解自动装配组件,你会了吗?》一文中得出的结论。那今天我们就使用其他的方式来实现cat的自动装配。

    标注在实例方法上

    我们也可以将@Autowired注解标注在setter方法上,如下所示。

    @Autowired
    public void setCat(Cat cat) {
        this.cat = cat;
    }
    

    当@Autowired注解标注在方法上时,Spring容器在创建对象的时候,就会调用相应的方法为对象赋值。如果标注的方法存在参数时,则方法使用的参数和自定义类型的值,需要从IOC容器中获取。

    接下来,我们将AutowiredTest类的testAutowired01()方法中有关获取和打印PersonService信息的代码注释,新增获取和打印Dog信息的代码,如下所示。

    @Test
    public void testAutowired01(){
        //创建IOC容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
        //PersonService personService = context.getBean(PersonService.class);
        //System.out.println(personService);
        Dog dog = context.getBean(Dog.class);
        System.out.println(dog.toString());
        context.close();
    }
    

    运行AutowiredTest类的testAutowired01()方法进行测试,可以看到,结果信息中输出了如下一行信息。

    Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
    

    说明已经获取到cat的信息,可以将@Autowired注解标注在方法上

    为了验证最终的输出结果是否是从IOC容器中获取的,我们可以在AutowiredTest类的testAutowired01()方法中直接获取Cat的信息,如下所示。

    @Test
    public void testAutowired01(){
        //创建IOC容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
        //PersonService personService = context.getBean(PersonService.class);
        //System.out.println(personService);
        Dog dog = context.getBean(Dog.class);
        System.out.println(dog.toString());
        Cat cat = context.getBean(Cat.class);
        System.out.println(cat);
        context.close();
    }
    

    我们再次运行AutowiredTest类的testAutowired01()方法进行测试,可以在输出的结果信息看到如下两行代码。

    Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
    io.mykit.spring.plugins.register.bean.Cat@6a400542
    

    可以看出在Dog类中通过@Autowired注解获取到的Cat对象和直接从IOC容器中获取到Cat对象是同一个对象。

    标注在构造方法上

    在前面的案例中,我们在Dog类上使用了@Component注解,如下所示。

    package io.mykit.spring.plugins.register.bean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    /**
     * @author binghe
     * @version 1.0.0
     * @description 测试实体类
     */
    @Component
    public class Dog {
    
        private Cat cat;
    
        public Cat getCat() {
            return cat;
        }
    
        @Autowired
        public void setCat(Cat cat) {
            this.cat = cat;
        }
    
        @Override
        public String toString() {
            return "Dog{" +
                    "cat=" + cat +
                    '}';
        }
    }
    

    此时,Spring默认加载IOC容器中的组件,IOC容器启动的时候默认会调用bean的无参构造器创建对象,然后再进行初始化赋值等操作。

    接下来,我们为Dog类添加一个有参构造方法,然后去除setCat()方法上的@Autowired注解,将@Autowired注解标注在有参构造方法上,并在构造方法中打印信息,如下所示。

    package io.mykit.spring.plugins.register.bean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    /**
     * @author binghe
     * @version 1.0.0
     * @description 测试实体类
     */
    @Component
    public class Dog {
        private Cat cat;
        @Autowired
        public Dog(Cat cat){
            this.cat = cat;
            System.out.println("调用了Dog的有参构造方法");
        }
        public Cat getCat() {
            return cat;
        }
        public void setCat(Cat cat) {
            this.cat = cat;
        }
        @Override
        public String toString() {
            return "Dog{" +
                    "cat=" + cat +
                    '}';
        }
    }
    

    接下来,我们运行AutowiredTest类的testAutowired01()方法进行测试,可以看到输出结果信息中存在如下一行信息。

    调用了Dog的有参构造方法
    

    说明IOC容器在启动的时候调用了Dog类的有参构造方法。并且可以从输出的如下两行信息可以看出:通过Dog类的toString()方法打印出的Cat对象和直接从IOC容器中获取的Cat对象是同一个对象。

    Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
    io.mykit.spring.plugins.register.bean.Cat@6a400542
    

    这里,需要大家注意的是:使用@Autowired注解标注在构造方法上时,构造方法中的参数对象也都是从IOC容器中获取的。

    标注在参数上

    我们也可以将@Autowired注解标注在参数上,例如,在Dog类中我们将构造方法上的@Autowired注解标注在构造方法的参数上,如下所示。

    public Dog(@Autowired Cat cat){
        this.cat = cat;
        System.out.println("调用了Dog的有参构造方法");
    }
    

    也可以将@Autowired注解标注在setter方法的参数上,如下所示。

    public void setCat(@Autowired  Cat cat) {
        this.cat = cat;
    }
    

    这些效果与标注在字段、实例方法和构造方法上的效果都是一样的。

    例如,我们将@Autowired注解标注在构造方法的参数上,运行AutowiredTest类的testAutowired01()方法进行测试,可以看到,输出结果中,同样包含如下三行信息。

    调用了Dog的有参构造方法
    Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
    io.mykit.spring.plugins.register.bean.Cat@6a400542
    

    结论:无论Autowired注解标注在字段上、实例方法上、构造方法上还是参数上,都是从IOC容器中获取参数组件的值。

    如果Spring的bean只有一个有参构造方法,并且这个有参构造方法只有一个参数,并且这个参数是IOC容器中的对象,当@Autowired注解标注在这个构造方法的参数上时,我们可以将@Autowired注解省略,如下所示。

    public Dog(Cat cat){
        this.cat = cat;
        System.out.println("调用了Dog的有参构造方法");
    }
    

    接下来,我们运行AutowiredTest类的testAutowired01()方法进行测试,从输出的结果信息中,可以看出,同样输出了下面的三行信息。

    调用了Dog的有参构造方法
    Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
    io.mykit.spring.plugins.register.bean.Cat@6a400542
    

    说明:如果Spring的bean只有一个有参构造方法,并且这个有参构造方法只有一个参数,并且这个参数是IOC容器中的对象,当@Autowired注解标注在这个构造方法的参数上时,我们可以将@Autowired注解省略。

    标注在方法位置

    @Autowired注解可以标注在某个方法的位置上。这里,为了更好的演示效果,我们新建一个Fish类,在Fish类中有一个Cat类型的成员变量,如下所示。

    package io.mykit.spring.plugins.register.bean;
    /**
     * @author binghe
     * @version 1.0.0
     * @description 测试类
     */
    public class Fish {
        private Cat cat;
        public void setCat(Cat cat) {
            this.cat = cat;
        }
        @Override
        public String toString() {
            return "Fish{" + "cat=" + cat + '}';
        }
    }
    

    接下来,我们在AutowiredConfig类中实例化Fish类,如下所示。

    @Bean
    public Fish fish(){
        return new Fish();
    }
    

    接下来,我们在AutowiredTest类中创建testAutowired02()方法,如下所示。

    @Test
    public void testAutowired02(){
        //创建IOC容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
        Fish fish = context.getBean(Fish.class);
        System.out.println(fish);
        context.close();
    }
    

    运行testAutowired02()方法,在输出的结果信息中存在如下一行信息。

    Fish{cat=null}
    

    说明此时的Fish类中的Cat对象为空。此时,我们可以将Cat对象作为一个参数传递到AutowiredConfig类的fish()方法中,并且将Cat对象设置到Fish中,如下所示。

    @Bean
    public Fish fish(Cat cat){
        Fish fish = new Fish();
        fish.setCat(cat);
        return fish;
    }
    

    当然,我们也可以使用@Autowired注解来标注fish()方法中的cat参数,如下所示。

    @Bean
    public Fish fish(@Autowired  Cat cat){
        Fish fish = new Fish();
        fish.setCat(cat);
        return fish;
    }
    

    接下来,我们再次运行testAutowired02()方法,在输出的结果信息中存在如下一行信息。

    Fish{cat=io.mykit.spring.plugins.register.bean.Cat@21de60b4}
    

    说明Cat对象被成功创建并设置到了Fish类中。

    结论:如果方法只有一个IOC容器中的对象作为参数,当@Autowired注解标注在这个方法的参数上时,我们可以将@Autowired注解省略。

    重磅福利

    关注「 冰河技术 」微信公众号,后台回复 “设计模式” 关键字领取《深入浅出Java 23种设计模式》PDF文档。回复“Java8”关键字领取《Java8新特性教程》PDF文档。回复“限流”关键字获取《亿级流量下的分布式限流解决方案》PDF文档,三本PDF均是由冰河原创并整理的超硬核教程,面试必备!!

    好了,今天就聊到这儿吧!别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!!

    写在最后

    如果你觉得冰河写的还不错,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发、分布式、微服务、大数据、互联网和云原生技术,「 冰河技术 」微信公众号更新了大量技术专题,每一篇技术文章干货满满!不少读者已经通过阅读「 冰河技术 」微信公众号文章,吊打面试官,成功跳槽到大厂;也有不少读者实现了技术上的飞跃,成为公司的技术骨干!如果你也想像他们一样提升自己的能力,实现技术能力的飞跃,进大厂,升职加薪,那就关注「 冰河技术 」微信公众号吧,每天更新超硬核技术干货,让你对如何提升技术能力不再迷茫!

  • 相关阅读:
    [示例] Firemonkey 面包屑导航
    [试玩] FMXLinux (Firemonkey for Linux) Linux 桌面开发(第三方插件)
    [修正] Firemonkey SpeedButton 鼠标移开按钮后 IsPressed 为 False 的问题
    [笔记] FireDAC DataSet 导入及导出 JSON
    [笔记] 升級到 Delphi 10.2 Tokyo 笔记
    [示例] 用代码设置 ListView 颜色 (只适用 Win 平台,无需修改官方源码)
    [上架] iOS 上架更新版本号建议
    [教学] Delphi IDE 文件搜寻功能
    Loadrunner相关问题
    数据导出excel数据丢失
  • 原文地址:https://www.cnblogs.com/binghe001/p/13510168.html
Copyright © 2011-2022 走看看