Spring 是一个开源的、轻量级的企业级 Java 应用程序框架,它提供了一种全新的、基于 IoC (控制反转)和 AOP(面向切面编程)的软件开发方式,以及众多的企业级应用程序开发组件和 API。使用 Spring 框架可以大大简化企业应用程序的开发,降低代码的耦合度和复杂度,提高应用程序的可维护性和可扩展性。
Bean的作用范围
<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
在 Spring 框架中,Bean 的作用范围(Scope)用来决定一个 Bean 实例的生命周期以及在应用中使用该 Bean 实例的方式。Spring 支持以下几种作用范围:
-
singleton:单例模式,即每一个 Bean 容器中只会创建一个 Bean 实例,每次使用时都返回同一个实例。(默认为此模式)
-
prototype:原型模式,即每次从 Bean 容器中获取该 Bean 实例时,都会创建一个新的实例。
-
session:Web 应用中的会话作用域,即每一个 HTTP 会话都对应一个单独的 Bean 实例。
-
request:Web 应用中的请求作用域,即每一个 HTTP 请求都对应一个单独的 Bean 实例。
-
global-session: 针对portlet的session作用域,属于portlet的全局作用域。
这些作用范围的选择取决于具体的业务需求和设计,可以根据不同的场景进行选择。
使用作用范围可以达到以下几个目的:
- 节约资源:使用单例模式可以避免在多次调用时重复创建实例,节约了资源。
- 控制对象的生命周期:通过设置不同的作用范围,可以控制 bean 对象的创建、初始化、销毁等过程。
- 实现特定的业务需求:有些场景下需要为不同的请求或会话创建独立的 Bean 实例,使用请求或会话作用范围可以满足这种需求。
bean的生命周期
public class AppForLifeCycle {
public static void main( String[] args ) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
//ctx.registerShutdownHook();
//关闭容器
ctx.close();
}
}
applicationContext.xml配置
bookServiceImpl
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
System.out.println("set .....");
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
BookDaoImpl
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
输出结果
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
加载上下文时就会触发bean的生命周期
概念
在 Spring 容器中,一个 Bean 的生命周期可以分为以下几个阶段:
- 实例化:Spring 容器通过反射机制创建一个 Bean 的实例。
- 设置属性:Spring 容器将配置文件中的属性值和对其它 Bean 的引用传递到 Bean 实例中,完成 Bean 的属性注入。
- 初始化前回调:如果 Bean 实现了 InitializingBean 接口,则调用其 afterPropertiesSet() 方法。
- 自定义初始化回调:如果在配置文件中配置了 init-method 属性,则调用其指定的初始化方法。默认情况下,该方法名称为 init()。
- 初始化后回调:如果 Bean 实现了 BeanPostProcessor 接口,则对所有 Bean 实例应用 postProcessBeforeInitialization() 方法。
- 初始化:Bean 实例已经完成了初始化,可以使用了。
- 初始化后回调:如果 Bean 实现了 BeanPostProcessor 接口,则对所有 Bean 实例应用 postProcessAfterInitialization() 方法。
- 使用:Bean 实例可以被应用程序使用了。
- 销毁前回调:如果 Bean 实现了 DisposableBean 接口,则调用其 destroy() 方法。
- 自定义销毁回调:如果在配置文件中配置了 destroy-method 属性,则调用其指定的销毁方法。默认情况下,该方法名称为 destroy()。
以上是一个典型的 Bean 生命周期的阶段,但并不是每个 Bean 都需要经历全部的阶段,具体的 Bean 生命周期会受到该 Bean 的具体实现、Spring 配置文件的设置等各种因素的影响。
bean扫描
方法一:xml配置
<context:component-scan base-package="com.itheima"/>
context:component-scan 标签会扫描以下四个注解:
- @Component:用于声明一个普通的组件类,通常作为其他组件类的基础组件使用。
- @Controller:用于声明 Web 控制器类,主要处理 HTTP 请求和响应,通常与 @RequestMapping 注解一起使用。
- @Service:用于声明服务类,通常作为业务逻辑的实现类使用,例如数据操作、事务管理等。
- @Repository:用于声明数据访问对象(DAO)类,通常实现对数据库或者其他存储介质的访问,例如 CRUD 操作、查询等。
以上注解都属于 Spring 提供的基本注解,可以通过在类上使用这些注解来告诉 Spring 框架如何管理和使用这些组件。在 Spring 应用程序中,通常会将这些注解用于标记需要被 Spring 容器管理的组件类,以便在运行时自动装配和使用这些组件。
需要注意的是,context:component-scan 标签会扫描指定包下的所有类,并将其中使用了以上注解的类自动注册为 Spring Bean。因此,在使用这个标签时,需要仔细选择需要扫描的基础包名,避免将不需要注册为 Spring Bean 的类也加入到 Spring 容器中。
方法二:java类配置
@Configuration
//设置bean扫描路径,多个路径书写为字符串数组格式
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}
@Configuration 注解表示这是一个配置类,用于声明 Spring 应用程序中的组件。通常情况下,我们会将所有相关的 Spring 配置信息放在一个或多个配置类中,以便在启动应用程序时加载和使用它们。
@ComponentScan 注解用于配置 Spring 的组件扫描功能,它可以告诉 Spring 框架在哪些包下扫描组件并将它们注册到 Spring 容器中。在上述代码中,它指定了两个需要扫描的包路径分别是 com.itheima.service 和 com.itheima.dao。
此外,@ComponentScan 注解还可以指定其他属性,例如过滤规则、扫描策略等,以便更加灵活地控制组件的扫描和管理。
综上所述,上述代码配置的 SpringConfig 类用于声明 Spring 配置信息和组件扫描路径,在启动应用程序时,Spring 框架会根据这些配置信息扫描指定的包路径,并自动注册扫描到的组件到 Spring 容器中,以便后续使用。
@Component注解和@Controller、@Service、@Repository三个衍生注解有什么区别?
- @Component、@Controller、@Service、@Repository 这四个注解都是 Spring 框架提供的用于描述组件的注解。它们之间的区别主要在于它们的作用范围和语义不同。
- @Component 注解是基本注解,用于声明一个普通的 Spring 组件类。它可以用于任何类型的组件类,通常作为其他高级注解的基础组件来使用。
- @Controller 注解用于声明一个 Spring MVC 的控制器类,用于处理 HTTP 请求和响应。通常与 @RequestMapping 注解一起使用。
- @Service 注解用于声明一个业务服务类,主要用于实现业务逻辑,例如数据操作、事务管理等。
- @Repository 注解用于声明一个数据访问对象(DAO)类,主要用于封装对数据库或者其他存储介质的访问,例如 CRUD 操作、查询等。
- 这些注解的目的是为了将 Java 类标记为 Spring 中的组件,以便在运行时进行组件扫描和自动装配。具体来说,在 Spring 应用程序中,这些注解通常会被用于标记需要被 Spring 容器管理的组件,以便在运行时自动装配和使用这些组件。
- 总的来说,@Controller、@Service、@Repository 等注解都是基于 @Component 注解衍生而来的,并且拥有更加具体的语义。在使用时,我们应该根据组件的作用和类型选择合适的注解,并将其用于标记相应的类。
@Autowired注解是如何进行自动装配的?
@Autowired 注解是 Spring 框架中用于进行自动装配的注解之一。它可以将容器中类型匹配的 Bean 实例自动注入到目标类中,从而实现依赖注入。
具体来说,当 Spring 容器检测到一个类中存在 @Autowired 注解时,它会根据被注解的字段或方法参数的类型,在容器中查找匹配的 Bean 实例,并将其自动注入到对应的字段或方法参数中,完成依赖注入的过程。
在进行自动装配时,Spring 框架会按照以下规则选择匹配的 Bean 实例:
- 根据被注解的字段或方法参数的类型选择匹配的 Bean 实例。如果有且仅有一个类型匹配的 Bean 实例,则自动装配成功。
- 如果有多个类型匹配的 Bean 实例,且这些 Bean 实例都没有指定主要实例,则 Spring 抛出异常。
- 如果有多个类型匹配的 Bean 实例,但这些 Bean 实例中只有一个指定了主要实例,则自动装配使用主要实例。
- 如果有多个类型匹配的 Bean 实例,且这些 Bean 实例都指定了主要实例,则 Spring 会根据 @Qualifier 注解指定的名称或者 Bean 实例的名称进行匹配,选择满足条件的 Bean 实例进行自动装配。
- 使用@Qualifier注解指定要装配的bean名称(@Qualifier注解无法单独使用,必须配合@Autowired注解使用)
作用:@Autowired 注解提供了一种方便的方式,可以帮助开发人员自动装配 Spring 容器中的 Bean 实例,从而简化了应用程序的配置和维护工作。
注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法。
遇到的一些问题
java: 不再支持源选项 5。请使用 7 或更高版本。
在项目的 pom.xml 文件中设置 maven.compiler.source 和 maven.compiler.target 属性的值为 7 或更高版本
<project>
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
...
</dependencies>
...
</project>
扫描失败
报错Exception encountered during context initialization - cancelling refresh attempt:
<context:component-scan base-package="com.itheima"/>
错误语句
解决办法:降版本,将java版本降为9