目录
Spring学习专栏
若本文讲解有描述错误之处,或者有错别字,欢迎指正,希望大家毫不吝啬。
一、概述
在正式分析Spring源码之前,我们有必要先来回顾一下Spring中最简单的用法。尽管我相信您已经对这个例子非常熟悉了。Bean是Spring中最核心的概念,因为Spring就像是个大水桶,而Bean就像是水桶中的水,水桶脱离了水也就没什么用处了。
二、搭建基础框架
1. XML方案搭建Spring容器
1. 引入jar包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
</dependencies>
引入 spring-context jar,它会自动帮我引入aop、beans、core、expression、jcl 如下图:
2. User实体类
/**
* User实体类
* @date: 2021/2/24 17:47
*/
public class User {
private String userName;
private Integer age;
public void setUserName(String userName) {
this.userName = userName;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
3. spring-config.xml 配置文件
在项目resources目录下创建spring-config.xml,把User实体类注入到Spring容器中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.zlp.spring.v1.entity.User">
<property name="age" value="10" />
<property name="userName" value="smile" />
</bean>
</beans>
4. XmlUserTest 测试类
/**
* XML容器测试类
* @author Zou.LiPing
* @date: 2021/2/24 17:13
*/
public class XmlUserTest {
private static ClassPathXmlApplicationContext applicationContext;
public static void main(String[] args) {
applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println(user.toString());
}
/**
* spring配置中beanId重复,会报错,还是会覆盖
* 会报错
*/
}
5. 控制打印输出
User{userName='smile', age=10}
2. Annotation方案搭建Spring容器
1. UserEntity实体类
@Component
public class UserEntity {
private String userName = "change";
private Integer age = 28;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
2. SpringConfig配置类
@Configuration
@ComponentScan("com.zlp.spring.v2")
public class SpringConfig {
}
3. AnnotationUserTest 测试类
/**
* 注解测试类
* @author Zou.LiPing
* @date: 2021/2/24 17:13
*/
public class AnnotationUserTest {
private static AnnotationConfigApplicationContext applicationContext;
public static void main(String[] args) {
applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserEntity user = applicationContext.getBean("userEntity", UserEntity.class);
System.out.println(user.toString());
// 打印注入Spring有哪些对象
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
4. 控制打印输出
User{userName='change', age=28}
三、几个QA?
1. Spring默认是单例还是多例?
默认单列模式(singleton),可以在类中添加作用域 @Scope(value = "prototype")
-
singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
-
prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
-
request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
-
session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
-
globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
2. Spring中@Lazy单例模式中的懒汉式和饿汉式
在单例模式默认懒汉模式,可以在类中添加@Lazy(value = false)
项目地址