zoukankan      html  css  js  c++  java
  • Spring注解之@Autowired:装配构造函数和属性

           在User类中创建一个构造函数,传入参数student:

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.Serializable;
    
    /**
     * @author Wiener
     */
    @Component
    public class User implements Serializable {
        private static final long serialVersionUID = 6089103683553156328L;
        private Long id;
    
        private Student student;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        @Autowired  // 构造函数注入参数的方式
        User(Student student) {
            this.student = student;
            System.out.println("------ 为构造器装配Bean成功 ---------");
        }
        public void isStu() {
            student.studentStudy();
            System.out.println("------ 装配Bean成功 ---------");
        }
    }

           其中,Student类如下:

    import lombok.Getter;
    import lombok.Setter;
    import org.springframework.stereotype.Component;
    
    import java.io.Serializable;
    import java.util.Date;
    
    /**
     * @author Wiener
     */
    @Getter
    @Setter
    @Component
    public class Student implements Serializable {
    
        private static final long serialVersionUID = -5246589941647210011L;
    
        //姓名
        private String name;
      
        public Student() {
            System.out.println("A default student constructor." );
        }
        public void studentStudy() {
            System.out.println("A student is studying." );
        }
    }

    改造Spring Boot项目启动类:

    import com.east7.bean.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ApplicationContext;
    
    /**
     * @author Wiener
     */
    @SpringBootApplication
    public class East7Application {
    
        public static void main(String[] args) {
           ApplicationContext act = SpringApplication.run(East7Application.class, args);
            User user = (User) act.getBean("user");
            user.isStu();
        }
    
    }

    执行测试函数后,控制台打印信息如下:

    A default student constructor.
    ------ 为构造器装配Bean成功 ---------
    A student is studying.
    ------ 装配Bean成功 ---------

           说明成员变量已经注入。此处需要注意一点,如果有两个自定义构造方法,而且都没加@Autowired注解,则会报错,因为Spring不知道你要用哪个构造方法初始化;如果只有一个构造方法加了@Autowired注解,那么就会用这个构造方法初始化;同理,如果有多个构造方法都加了@Autowired注解,那么还是会报错提示Only one constructor can have @Autowired annotation。

           可以在属性中使用@Autowired 注解来省略 setter 方法。当使用@Autowired为自动连接属性传递的时候,Spring 会将这些传递过来的值或者引用自动分配给那些属性。像下面这样写在属性上并直接引用会报空指针异常:

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
    * @author Wiener
    */
    @Component
    public class User {
    
        @Autowired //变量注入方式
        private Student student;
        private Long id = student.getId();
    
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public void isStu() {
            id = student.getId();
            student.studentStudy();
            System.out.println("------ 装配Bean成功 ---------");
        }
    }

    异常信息如下:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'user' defined in file [xxxxxxUser.class]: 
    Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException:
    Failed to instantiate [com.east7.bean.User]:
    Constructor threw exception; nested exception is java.lang.NullPointerException

    报错信息提示创建Bean时出错,因为实例化bean时构造方法抛出了空指针异常。如果仅仅使用函数isStu()初始化变量id, 并且把【private Long id = student.getId();】改为 【private Long id;】,则属于方法调用的时候初始化,此时,bean已经注入,不会抛异常。 

           其实这两种方式都可以使用,但报错的原因是加载顺序的问题,@autowired写在变量上的注入要等到类完全加载后,才会将相应的bean注入,而变量是在加载类的时候按照相应顺序加载的,所以变量的加载要早于被@autowired注解的变量,那么给变量prefix 赋值的时候所使用的a,其实还没有被注入,所以报空指针,而使用构造器则会在加载类的时候将a加载,这样在内部使用a给prefix 赋值就完全没有问题。 

           如果不使用构造器,那么也可以不给prefix 提前赋值,而是在系统启动后,变量prefix被使用的地方,通过a.getExcelPrefix()进行赋值,此时对a的使用是在类完全加载之后,即a被注入后,所以也是可以的。 

           总之,@Autowired一定要等本类构造完成后,才能从外部引用设置属性,所以@Autowired的注入时间一定会晚于构造函数的执行时间。但在初始化变量的时候就使用了还没注入的bean,所以导致了NPE。若在初始化其它变量时不使用这个要注入的bean,而是在后期调用方法的时候去初始化,是可以使用这个bean的,因为那时构造函数已经执行完毕,即已注入bean了。一言以蔽之,Java变量的初始化顺序为:静态变量或静态语句块–>实例变量或初始化语句块–>构造函数–>@Autowired 注入Bean

  • 相关阅读:
    第二代:晶体管计算机
    第一代计算机
    Android应用在不同版本间兼容性处理
    eventBus
    realm
    ijkplayer详解AAA
    USB 3.0规范中译本 第3章 USB 3.0体系结构概览
    ES6 学习笔记
    07_通过上下文获取常见目录
    06_登陆案例保存信息完成
  • 原文地址:https://www.cnblogs.com/east7/p/13283586.html
Copyright © 2011-2022 走看看