Bean的自动装配及作用域

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Bean的自动装配及作用域

点击蓝字“程序员考拉”欢迎关注!

Bean的自动装配及作用域

1.XML配置里的Bean自动装配

Spring IOC 容器可以自动装配 Bean,需要做的仅仅是在 bean 的 autowire 属性里指定自动装配的模式。自动装配方式有:

  • byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配.
  • byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同.
  • 示例代码:

    Person.java,Person里面有三个属性:name,address,car。

    
    package com.java.spring.autowire;
    
    public class Person {
      private String name;
      private Address address;
      private Car car;
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
      public Address getAddress() {
        return address;
      }
      public void setAddress(Address address) {
        this.address = address;
      }
      public Car getCar() {
        return car;
      }
      public void setCar(Car car) {
        this.car = car;
      }
      @Override
      public String toString() {
        return "Person [name=" + name + ", address=" + address + ", car=" + car + "]";
      }
    }
    

    Address.java

    
    package com.java.spring.autowire;
    
    public class Address {
      private String city;
      private String street;
      public String getCity() {
        return city;
      }
      public void setCity(String city) {
        this.city = city;
      }
      public String getStreet() {
        return street;
      }
      public void setStreet(String street) {
        this.street = street;
      }
      @Override
      public String toString() {
        return "Address [city=" + city + ", street=" + street + "]";
      }
    }
    

    Car.java

    
    package com.java.spring.autowire;
    
    public class Car {
    
      private String brand;
      private double price;
      public String getBrand() {
        return brand;
      }
      public void setBrand(String brand) {
        this.brand = brand;
      }
      public double getPrice() {
        return price;
      }
      public void setPrice(double price) {
        this.price = price;
      }
      @Override
      public String toString() {
        return "Car [brand=" + brand + ", price=" + price + "]";
      }
    }
    

    1.1 使用byName进行自动装配

    使用byName根据bean的名字和当前bean的setter风格的属性名进行自动装配,若有匹配的自动转配,没有匹配的赋值为空。

    
    bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"/bean
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byName"/bean
    

    运行后输出:

    
    Person [name=Tom, address=Address [city=上海, street=南京路], car=Car [brand=Audi, price=500000.0]]
    

    若配置如下:

    
    bean id="address1212" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"/bean
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byName"/bean
    

    address1212与setter风格的属性名address不一致,则address不能被赋值:

    
    Person [name=Tom, address=null, car=Car [brand=Audi, price=500000.0]]
    

    1.2 使用byType进行自动装配

    byType根据bean的类型和当前bean的属性的类型进行自动装配,若IOC容器中有1个以上的类型匹配的bean,则抛异常。

    
    bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"/bean
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byType"/bean
    

    运行后输出:

    
    Person [name=Tom, address=Address [city=上海, street=南京路], car=Car [brand=Audi, price=500000.0]]
    

    若配置如下:

    
    bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"/bean
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="car1231" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" autowire="byType"/bean
    

    抛异常显示:(原因是有两个Car类型的bean)

    
    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.java.spring.autowire.Car] is defined: expected single matching bean but found 2: car,car1231
    

    在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性. 然而, 若只希望装配个别属性时, autowire 属性就不够灵活了. autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之.一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

    2.Bean之间的关系:继承和依赖

    2.1 Spring 允许继承 Bean 的配置, 被继承的 Bean 称为父 Bean. 继承这个父 Bean 的 Bean 称为子 Bean。子 Bean可以 从父 Bean 中继承配置, 包括 Bean 的属性配置,子 Bean 也可以覆盖从父 Bean 继承过来的配置。

    
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="car2" class="com.java.spring.autowire.Car" p:price="300000.0000" parent="car"/bean
    

    在主方法中获取Bean实例:

    
    Car car=(Car) ctx.getBean("car2");
    

     运行后输出:

    
    Car [brand=Audi, price=300000.0]
    

    2.2 父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 bean 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean。

    若设置为抽象Bean,则不能被实例化。

    
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000" abstract="true"/bean
    

    在主方法中获取实例:

    
    Car car=(Car) ctx.getBean("car");
    

    报异常:

    
    Exception in thread "main" org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'car': Bean definition is abstract
    

    并不是 bean 元素里的所有属性都会被继承. 比如: autowire, abstract 等.也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true。

    2.2 Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好。如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置Bean 的名称。

    
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" p:address-ref="address" depends-on="car"/bean
    

    若没有配置car这个Bean,则会报错。

    3.Bean的作用域

    3.1 singleton

    在 Spring 中, 可以在 bean 元素的 scope 属性里设置 Bean 的作用域. 默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为singleton, 它是所有 Bean 的默认作用域。

    
    bean id="address" class="com.java.spring.autowire.Address" p:city="上海" p:street="南京路"/bean
    bean id="car" class="com.java.spring.autowire.Car" p:brand="Audi" p:price="500000.0000"/bean
    bean id="person" class="com.java.spring.autowire.Person" p:name="Tom" p:address-ref="address" p:car-ref="car"/bean
    

    在主方法中获取实例:

    
    public class Main {
      public static void main(String[] args){
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-relation.xml");
        Person person1=(Person) ctx.getBean("person");
        Person person2=(Person) ctx.getBean("person");
        System.out.println(person1==person2);
      }
    

     System.out.println(person1==person2);打印结果为true,person1和person2为同一个对象。

    3.2 prototype

    原型的,容器初始化时不创建Bean实例,而是在每次请求时都创建一个新的Bean实例并返回。

    Bean的自动装配及作用域
    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Bean的自动装配及作用域


     上一篇
    Spring界的HelloWorld Spring界的HelloWorld
    点击蓝字“程序员考拉”欢迎关注! 1.Spring依赖的jar包下载网址: https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-l
    2021-04-05
    下一篇 
    Spring中的Bean配置方式 Spring中的Bean配置方式
    点击蓝字“程序员考拉”欢迎关注! 1.IOC和DI概述 IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应
    2021-04-05