小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
=
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 的同一个实例。
在 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 作用域。
在 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 异常。