Spring——bean作用域和自动装配

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

=

Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域。

Scope Description
singleton(常用) 单例模式,使用 singleton 定义的 Bean 在 Spring 容器中只有一个实例,这也是 Bean 默认的作用域。
prototype(常用) 原型模式,每次通过 Spring 容器获取 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。
request 在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。
session 在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。
application 将单个 bean 定义的范围限定为ServletContext的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
websocket 将单个 bean 定义的范围限定为WebSocket的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。

1、bean作用域

1、singleton 作用域

singleton 是 Spring 容器默认的作用域,当一个 Bean 的作用域为 singleton 时,Spring 容器中只会存在一个共享的 Bean 实例,并且所有对 Bean 的请求,只要 id 与该 Bean 定义相匹配,就只会返回 Bean 的同一个实例。

img

在 Spring 配置文件中,可以使用 <bean> 元素的 scope 属性,将 Bean 的作用域显示定义成 singleton,其配置方式如下所示:

<bean id="user" class="com.cheng.pojo.User" scope="singleton"/>
复制代码
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = context.getBean("user", User.class);
        User user1 = context.getBean("user", User.class);
        System.out.println(user==user1);//true
复制代码

结果为true,这说明 Spring 容器只创建了一个 User类的实例。由于 Spring 容器默认作用域是 singleton,如果不设置 scope="singleton",则其输出结果也将是一个实例。

2、prototype 作用域

使用 prototype 作用域的 Bean 会在每次请求该 Bean 时都会创建一个新的 Bean 实例。因此对需要保持会话状态的 Bean应该使用 prototype 作用域。

img

在 Spring 配置文件中,要将 Bean 定义为 prototype 作用域,只需将 元素的 scope 属性值定义成 prototype,其示例代码如下所示:

<bean id="user2" class="com.cheng.pojo.User" c:name="万里" c:age="3" c:address-ref="address" scope="prototype"/>

复制代码
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user2", User.class);
User user1 = context.getBean("user2", User.class);
System.out.println(user==user1);//false
复制代码

两次输出的结果并不相同,这说明在 prototype 作用域下,Spring 容器创建了两个不同的 Person 实例。

2、bean的自动装配

什么是自动装配:

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring容器可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。

要使用自动装配,就需要配置 <bean> 元素的 autowire 属性。autowire 属性有五个值,具体说明如下表。

名称 说明
byName 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。
byType 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。
constructor 根据构造方法的参数的数据类型,进行 byType 模式的自动装配。
autodetect 如果发现默认的构造方法,则用 constructor 模式,否则用 byType 模式。
no 默认情况下,不使用自动装配,Bean 依赖必须通过 ref 元素定义。

环境搭建

package com.cheng.pojo;

public class Person {
    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat(){
        return cat;
    }
    public void setCat(Cat cat){
        this.cat=cat;
    }
    public Dog getDog(){
        return dog;
    }
    public void setDog(Dog dog){
        this.dog=dog;
    }
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name=name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}
复制代码
package com.cheng.pojo;

public class Dog {
    public void shout(){
        System.out.println("wang~");
    }
}
复制代码
package com.cheng.pojo;

public class Cat {
    public void shout(){
        System.out.println("miao~");
    }
}
复制代码

byName自动装配

byName:会自动在容器上下文查找,和自己对象set方法后面的值对应的<bean>id,必须保证<bean>id全局唯一

<bean id="cat" class="com.cheng.pojo.Cat"/>
<bean id="dog" class="com.cheng.pojo.Dog"/>    
<bean id="person" class="com.cheng.pojo.Person" autowire="byName">
    <property name="name" value="万里"/>
</bean>
复制代码

byType自动装配

byType:会自动在容器上下文查找,和自己对象属性类型对应的<bean>,必须保证<bean>类型全局唯一

<bean id="cat" class="com.cheng.pojo.Cat"/>
<bean id="dog111" class="com.cheng.pojo.Dog"/>    
<bean id="person" class="com.cheng.pojo.Person" autowire="byName">
    <property name="name" value="万里"/>
</bean>
复制代码

3、使用注解实现自动装配

Java 从 JDK 5.0 以后,提供了 Annotation(注解)功能,Spring 从2.5也提供了对 Annotation 技术的全面支持。

使用注解要导入的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解的支持-->
    <context:annotation-config/>

</beans>
复制代码

常用的注解如下。

1)@Component

可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。

2)@Repository

用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

3)@Service

通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

4)@Controller

通常作用在控制层,用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

5)@Autowired

用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。直接在属性或者set方法上使用即可,如果在属性上使用了@Autowired,可以忽略该属性的set方法。

@Autowired
private Cat cat;
@Autowired
public void setDog(Dog dog){
     this.dog=dog;
    }
复制代码

补充:

  • @Nullable 字段标记了这个注解,说明该字段可以为空。

    public void setName(@Nullable String name){  //name属性可以为空了
        this.name=name;
        }
    复制代码
  • //如果显示的定义了@Autowired(required = false),则说明当前bean对象可以为null
    @Autowired(required = false)
    复制代码

6)@Qualifier

与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,当一个类型的Bean有多个实例名称时,实例名称由 @Qualifier 注解的参数指定。

<bean id="cat1" class="com.cheng.pojo.Cat"/>
<bean id="cat2" class="com.cheng.pojo.Cat"/>
<bean id="cat3" class="com.cheng.pojo.Cat"/>
复制代码

@Qualifier的使用

@Autowired
@Qualifier(value="cat2")
private Cat cat;
复制代码

7)@Resource

其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。

@Resource 中有两个重要属性:name 和 type。

Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。

如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。

猜你喜欢

转载自juejin.im/post/7018921221668470815
今日推荐