第四步:为对象设计作用域,设置延迟加载,设置生命周期方法(了解)。
在 Spring 框架中,Spring 为由它创建和管理的对象,设计了一些特性,例如作用域, 延迟加载,生命周期方法等,基于这些特性实现对 Bean 对象的管理。
package com.cy.pj.common.cache;
@Component
@Scope("singleton")
//作用域,如果不写默认为单例,写上则有两个属性 "singleton"与"prototype"
@Lazy //使用场景:不是实时使用,则延迟加载,默认属性 true 为延迟加载,也叫按需加载
public class DefaultCache {
public DefaultCache() {
System.out.println("cache()");
}
@PostConstruct //生命周期初始化方法,在对象构建完成后执行,用于初始化一些资源
public void init() {
System.out.println("init()");
}
@PreDestroy //生命周期销毁方法,对象销毁之前执行,用于释放一些资源
public void destory() {
System.out.println("destory");
}
}
其中:
- @Scope 是 Spring 中用于定义 Bean 对象作用域的一个注解,其常用的值有 singleton(整个内存有一份 Bean 实例,此实例何时创建与类的延迟加载特性配置有关,此实例创建以后,生命周期会由 Spring 框架管理),prototype(每次获取都会创建新实例,此实例会在需要时创建与 lazy 特性无关,这个实例创建以后,不会交给Spring 管理,Spring 可以对其初始化,但不负责销毁。)等。
- @Lazy 注解用于描述类,其目的是告诉 Spring 框架此类支持延迟加载,通常会配合单例作用域使用。
- @PostConstruct 注解用于描述 bean 对象生命周期方法中的初始化方法,此方法会在对象的构造方法之后执行。生命周期都有,但是生命周期方法不一定有。
- @PreDestroy 注解用于描述 Bean对象生命周期方法中的销毁方法,此方法会在对象销毁之前执行(当作用域为 prototype时,此方法不会执行)。
第五步:通过测试类测试作用域,延迟加载,生命周期方法。
package com.cy.pj.common.cache;
@SpringBootTest
public class DefaultCacheTests {
/*** @Autowired 描述属性时,表示此属性的值要由 spring 框架进行注入 */
@Autowired
private DefaultCache defaultCache;
@Autowired
private DefaultCache cache;
@Test
public void testDefaultCache() {
System.out.println(defaultCache);
}
@Test
public void testDefaultCache() {
System.out.println(defaultCache == cache);
}
}
通过对上面小节的学习,能说说 Spring 框架管理 Bean 对象有什么优势吗?低耗,高效.
Spring 是一个资源整合框架(Framework),通过 Spring 可将很多资源(自己写的对象或第三方提供的对象,例如连接池等)整合在一起,然后进行科学应用(例如解耦),以便 更好的对外提供服务。如图-17 所示:
图-17
在图-17 中,Spring 框架可以为由它管理的对象(Bean)提供懒加载策略(对象暂时用不到,则无需加载和实例化),作用域(例如 singleton-频繁用时可以考虑内存中只有一份,prototype-使用次数少时可以用时创建,不用时销毁),生命周期方法(更好实现对象的初始化和资源销毁),以实现对象对系统资源的有效使用。同时 Spring 框架还可以基于用户设计管理对象与对象的依赖关系,以降低对象与对象之间的直接耦合,提高程序的可维护性和可扩展性。
3.4 项目业务增强实现及测试
第一步:定义业务Cache接口.
package com.cy.pj.common.cache;
public interface Cache {}
第二步:定义WeakCache实现Cache接口.
package com.cy.pj.common.cache;
import org.springframework.stereotype.Component;
@Component//(cache01)存到 map 中用的为 cache01 作为 Key 而不是 weakCache
public class WeakCache implements Cache{}
//存入原材料库 Map<String,BeanDefinition>
//还有实例库 Map<String,Object>
第三步:修改DefaultCache,让此类也实现Cache接口,关键代码如下:
package com.cy.pj.common.cache;
@Component
public class DefaultCache implements Cache{
…
}
第四步:单元测试类
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class CacheTests {
@Autowired
//如还有一个类 SoftCache,让它存入 map 中也叫 defaultCache,那么报错
@Qualifier("defaultCache")
private Cache cache01;
@Test
public void testCache01() {
System.out.println(cache01);
}
}
package com.cy.pj.common.cache;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class CacheTests {
@Autowired
@Qualifier("defaultCache")
private Cache cache;
//@Autowired
//@Qualifier("weakCache")
public Cache cache02;
//测试类默认执行无参构造
//public CacheTests() {}
//构造方法注入
@Autowired
public CacheTests(@Qualifier("weakCache")Cache cache02) {
this.cache02 = cache02;
}
@Test
public void testCache01() {
System.out.println(cache);
}
@Test
public void testCache02() {
System.out.println(cache02);
}
}
业务测试运行原理分析,如图-18所示:
图-18
思考:
- @Autowired注解应用规则?
- @Qualifier注解的作用是什么?
@Autowired由Spring框架定义,用于描述类中属性或相关方法。Spring框架在项目运行时假如发现由他管理的Bean对象中有使用@Autowired注解描述的属性或方法,可以按照指定规则为属性赋值(DI)。其基本规则是:首先要检测容器中是否有与属性或方法参数类型相匹配的对象,假如有并且只有一个则直接注入。其次,假如检测到有多个,还会按照@Autowired描述的属性或方法参数名查找是否有名字匹配的对象,有则直接注入,没有则抛出异常。最后,假如我们有明确要求,必须要注入类型为指定类型,名字为指定名字的对象还可以使用@Qualifier注解对其属性或参数进行描述(此注解必须配合@Autowired注解使用)。具体过程可参考图-18的设计进行自行尝试和实践。
4 Spring Boot 小节总结(自学)
4.1 重难点分析
- Spring Boot 是什么? (脚手架而非框架)
- Spring Boot 核心优势?(启动依赖,自动配置-开箱即用,健康检查-系统监控)
- Spring Boot 项目的创建方式?( https://start.spring.io)
- Spring Boot 项目启动时,Bean的初始化过程是怎样的?(查找,加载,读和存储配置,创建和存储实例对象)
- Spring Boot 项目启动时,Bean对象的依赖注入过程是怎样的?(标记,查找,注入)
4.2 FAQ分析
- Maven工具(项目构建工具)从哪里下载?(maven.apache.org)
- STS(集成了Spring插件的eclipse)工具从哪里下载?(spring.io/tools)
- STS新版本怎么安装?(例如STS4.5.0的安装可使用:java -jar xxx.jar)
- 创建Spring Starter 项目时pom.xml文件错误?(工具版本,maven私服,本地库,maven update,网络)
- Spring Boot项目中支持的配置文件后缀有哪些?(.properties,.yml,.factories)
- Spring Boot 启动类的包扫描位置?(启动类所在包以及子包)
- Spring Boot项目中可以有多个启动类吗?(不可以)
- 如何理解Spring框架?(资源整合框架,科学应用对象-资源,解耦)
- Spring管理bean对象时有什么优势?
4.3 BUG分析
- Maven项目的settings文件配置错误,如图-19所示:
图-19
问题分析:检查maven目录中的settings.xml的标签语法配置是否正确
- 创建项目时网络连接超时,如图-20所示:
图-20
- Maven项目的pom.xml文件报错,如图-21所示:
图-21
问题分析:
- 检查网络配置(是否网络畅通)
- 检测maven配置是否正确(严格按文档配置执行)
- 右键项目maven update 强制更新
- 更换maven 私服仓库(选文档中的)
- 空指针异常(NullPointerException),如图-22所示:
图-22
问题分析:分析错误描述,找到自己写的类指定行号位置,看看哪个对象在进行方法调用,调用方法的对象有没有被赋值。
- 依赖注入失败,如图-23所示:
图-23
问题分析:
检查错误代码中自己定义的类(例如DefaultCacheTests)中的属性
基于错误分析,哪个属性的值在进行依赖注入时失败了(例如DefaultCache)
检查注入失败的属性对应的对象是否交给了Spring管理(例如是否有特定注解描述,包结构是否正确)
- 找不到对应的Bean对象,如图-24所示:
图-24
问题分析:
- 检查你获取的这个对象实例的类型是否使用了特定注解描述
- 检查你获取的这个对象实例的类型所在的包是否正确
- 假如是基于Bean的名字进行Bean对象的获取,要检测Bean的名字是否正确
- 依赖注入失败,如图-25所示:
图-25
问题分析:
- 检查哪里对Cache进行了引用。
- 检查对Cache引用时使用的注解描述。
- 检查容器中Cache接口下实现类对象的定义(是否有多个?)。