Spring
@Autowired和@Resource区别?
定义上的不同
@Autowired
对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
@Resource
在语义上被定义为通过其唯一的名称来标识特定的目标组件,其中声明的类型与匹配过程无关。
如果没有明确指定名称,则默认名称是从字段名称或设置方法(get、set方法)派生的。 如果用在字段上,则采用字段名称; 如果用在在setter方法,它采用其属性名称(例如setProperty()方法,取property做为属性名称)。
注解的属性不同
@Autowired只包含一个参数:required,表示是否开启自动注入,默认是true。而@Resource包含七个参数,其中最重要的两个参数是:name 和 type。如下:
public @interface Autowired {
/**
* 是否开启自动注入,有些时候我们不想使用自动装配功能,可以将该参数设置成false。
*/
boolean required() default true;
}
public @interface Resource {
/**
* bean的名称
*/
String name() default "";
String lookup() default "";
/**
* Java类,被解析为bean的类型
*/
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
/**
* 身份验证类型
*/
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
/**
* 组件是否可以与其他组件之间共享
*/
boolean shareable() default true;
String mappedName() default "";
/**
* 描述
*/
String description() default "";
}
默认装配不同
@Autowired如果要使用byName,需要使用@Qualifier一起配合。而@Resource如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配。
使用地方不同
@Autowired能够用在:构造器、方法、参数、成员变量和注解上,而@Resource能用在:类、成员变量和方法上。
来源不同
@Autowired是Spring定义的注解,而@Resource是JSR-250定义的注解。所以@Autowired只能在Spring框架下使用,而@Resource则可以与其他框架一起使用。
装配方式不同
@Autowired的装配顺序如下:
@Autowired默认先按byType进行匹配,如果发现找到多个bean,则又按照byName方式进行匹配,如果还有多个,则报出异常。
@Resource的装配顺序如下:
如果同时指定了name和type,流程如下:
如果指定了name,流程如下:
只是指定了@Resource注解的name,则按name后的名字去bean元素里查找有与之相等的name属性的bean。
如果指定了type,流程如下:
只指定@Resource注解的type属性,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常。
如果既没有指定name,也没有指定type,流程如下:
既不指定name属性,也不指定type属性,则自动按byName方式进行查找。如果没有找到符合的bean,则回退为一个原始类型进行进行查找,如果找到就注入。
AI问答
Q:Spring的IOC是指控制反转,将创建对象交给框架,我的疑问是当我使用注解来注入一个对象到controller或者service,这个过程是Spring实现是吧,是怎么实现的?
A:是的,当你在Spring框架中使用注解来注入一个对象到Controller或Service时,这个过程是由Spring框架自动实现的。具体实现机制大致可以分为以下几个步骤:
-
扫描与注册Bean:
- 组件扫描:Spring会根据
@ComponentScan
注解(通常在配置类上)指定的包路径,扫描该包及其子包下的所有带有特定注解的类(如@Component
、@Service
、@Repository
、@Controller
等),并将这些类识别为Bean定义。 - Bean定义注册:扫描到的类会被注册为Bean定义,保存在Spring容器中。每个Bean定义包含了如何创建该Bean实例的信息,比如类名、作用域、依赖关系等。
- 组件扫描:Spring会根据
-
依赖解析与注入:
- 依赖注入注解:在需要依赖的对象中,你可以使用
@Autowired
注解来标记需要注入的字段或方法,Spring会自动查找匹配的Bean并注入。如果存在多个匹配的Bean,可以通过@Qualifier
注解来指定具体的Bean名称。 - 构造器注入与Setter注入:Spring支持通过构造器和Setter方法进行依赖注入。当一个Bean的构造器或Setter方法带有
@Autowired
注解时,Spring会在创建Bean实例时解析这些依赖,并调用相应的构造器或Setter方法来注入依赖的Bean。
- 依赖注入注解:在需要依赖的对象中,你可以使用
-
Bean的生命周期管理:
- 实例化:当请求一个Bean时,Spring首先检查是否已经存在该Bean的实例,如果没有,则根据Bean定义创建一个新的实例。
- 初始化前处理:实例化后,Spring会调用初始化回调方法(如实现了
InitializingBean
接口的afterPropertiesSet
方法,或使用@PostConstruct
注解的方法)。 - 属性注入:在初始化回调之前或之后(根据配置),Spring会解析Bean定义中的依赖关系,并执行相应的依赖注入。
- 使用:Bean准备就绪后,可以被应用程序的其他部分使用。
- 销毁:当容器关闭时,Spring会调用销毁回调方法(如实现了
DisposableBean
接口的destroy
方法,或使用@PreDestroy
注解的方法)来清理资源。
整个过程是基于Spring的BeanFactory(更具体的是ApplicationContext,它是BeanFactory的扩展)实现的,它负责管理Bean的定义、创建、配置和生命周期。这一切都是通过反射、代理(如JDK动态代理或CGLIB)等技术在运行时动态完成的,使得开发者无需手动编写繁琐的工厂模式或服务定位器模式代码,大大简化了应用的架构和开发过程。
Q:spring容器中是只能存在一个相同的Bean对象吗?
A:在Spring容器中,是否能存在多个相同类型的Bean对象,取决于这些Bean的定义中设置的作用域(Scope)。Spring支持多种作用域,主要有以下几种:
-
singleton(单例):这是默认的作用域。当一个Bean定义为singleton时,Spring容器中只会存在一个该类型的Bean实例,每次请求该Bean时,Spring都会返回同一个共享的实例。这意味着,在整个应用的上下文中,相同类型的Bean都是同一个对象。
-
prototype(原型):如果将Bean定义为prototype,那么每当请求获取该类型的Bean时,Spring都会创建一个新的实例。这意味着在容器中可以有多个相同类型的Bean实例,每个实例都是独立的。
-
request(请求):在Web应用中,每次HTTP请求都会创建一个新的Bean实例,该作用域仅在Spring Web环境中有效。
-
session(会话):同样在Web应用中,每个HTTP Session对应一个Bean实例,也仅在Spring Web环境中有效。
-
globalSession(全局会话):主要用于Portlet环境中的全局会话作用域。
因此,简单来说,如果一个Bean定义为singleton作用域,那么Spring容器中只能存在一个相同的Bean对象;而如果定义为prototype或其他某些特定作用域,就可以存在多个不同的实例。
Q:都会创建一个新的Bean实例,那怎么区分哪个Bean对应哪个controller或者service?
A:在Spring框架中,尽管你可能会有多个相同类型的Bean实例(特别是当它们被定义为prototype作用域时),Spring仍然能够准确地管理并区分这些Bean实例,确保它们被正确地注入到需要它们的Controller或Service中。这主要通过以下几种方式实现:
-
Bean的ID或Name:每个Bean在定义时都会有一个唯一的ID或Name(在XML配置中通过
id
或name
属性指定,在注解配置中通常是类名首字母小写作为默认Bean名称,也可以通过@Component("自定义名称")
等方式指定)。Spring容器内部通过这些ID或Name来唯一标识每一个Bean实例。 -
依赖注入时的限定符:当有多个相同类型的Bean且需要注入到某个Controller或Service时,可以通过
@Qualifier
注解来指定确切的Bean名称,以告知Spring应该注入哪一个实例。例如,@Autowired @Qualifier("specificBeanName") MyService myService;
。 -
自动装配的逻辑:Spring在进行依赖注入时,会考虑Bean的类型、名称、以及
@Qualifier
等注解来精确匹配依赖项。对于原型(prototype)作用域的Bean,即使类型相同,Spring也能通过请求的上下文(如request或session)来区分不同的实例。 -
作用域代理:特别是对于prototype作用域的Bean,如果它们被注入到singleton作用域的Bean中,Spring会自动创建一个代理来管理原型Bean的生命周期。这个代理会在每次调用时动态地创建或获取一个新的prototype Bean实例,同时确保singleton Bean持有的引用仍然是有效的。
总结来说,通过Bean的名称、限定符注解、以及Spring内部的自动装配逻辑和作用域代理机制,Spring能够确保每个Controller或Service都能得到其预期的Bean实例,即便存在多个相同类型的实例。
SpringBoot
Spring和SpringBoot区别?
配置文件
application.yml 基础配置
默认的主配置文件,Spring Boot 应用会自动加载该文件。存放应用程序的主要配置。是 Spring Boot 中用于配置应用程序属性的主要配置文件之一。这个文件
通常用于配置应用程序的一般性属性,包括数据库连接、日志级别、端口
号等。下面是一些常见的在 application.yml 中配置的示例:
# 服务器端口
server:
port: 8080
# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydatabase
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
# 日志级别
logging:
level:
root: INFO
com.example.mypackage: DEBUG
# 应用程序自定义属性
myapp:
name: My Spring Boot App
version: 1.0
上述示例展示了一些常用的配置项,但根据应用程序的需求,你可以在 application.yml 中配置各种属性。Spring Boot 非常灵活,可以根据属性的前缀识别属性,并将其绑定到对应的 Java 对象上,以方便在代码中使用。
需要注意的是,application.yml 文件采用 YAML(YAML Ain’t Markup Language)语法,它使用缩进和冒号来表示层次关系。因此,正确的缩进对于保持文件的结构是很重要的。
application-{profile}.properties/application-{profile}.yml:
可以根据不同的环境配置不同的属性文件,{profile} 表示环境名称。
例如,application-dev.properties 用于开发环境,application-prod.properties用于生产环境。
bootstrap.properties/bootstrap.yml
用于 Spring Cloud 应用,是 Spring Cloud Config 服务的默认配置文件。
存放一些启动时需要优先加载的配置,比如连接到 Config Server 的配置。
application-{label}.properties/application-{label}.yml
用于 Git 和配置服务器的外部化配置,{label} 表示 Git 的标签。
例如,application-v1.properties 用于版本 1。
这些文件命名规范允许你根据不同的环境、配置标签或者配置文件类型组织和管理你的配置信息。Spring Boot 会根据上述规则自动加载相应的配置文件。
多配置文件,怎么知道用哪个?
Spring Boot 在启动时会加载默认的主配置文件,即 application.yml 或 application.properties。如果有不同环境的配置文件,如 application-test.yml 或 application-dev.yml,Spring Boot 会根据当前激活的环境来选择加载对应的配置文件。
配置文件设置 spring.profiles.active 指定激活环境
你可以通过在 application.yml 或 application.properties 中设置 spring.profiles.active 属性来指定激活的环境。例如:
spring:
profiles:
active: dev
上述配置表示激活 dev 环境,因此 Spring Boot 会加载 application-dev.yml 文件中的配置。
如果没有设置 spring.profiles.active 属性,Spring Boot 将默认使用主配置文件的配置。
命令行参数指定环境
除了通过属性文件来设置激活的环境外,你还可以通过命令行参数、系统属性、环境变量等方式来指定激活的环境。例如,通过命令行参数启动时指定环境:
java -jar your-application.jar --spring.profiles.active=dev
这样就会加载 application-dev.yml 的配置。
tips:Springboot中配置文件的加载顺序
application.yml、application.properties和bootStrap.yml加载顺序
以jar包发布springboot项目时
默认会先使用jar包根目录下的application.properties来作为项目配置文件。
如果在不同的目录中存在多个配置文件,它的读取顺序是:
1、config/application.properties(项目根目录中config目录下)
2、config/application.yml
3、application.properties(项目根目录下)
4、application.yml
5、resources/config/application.properties(项目resources目录中config目录下)
6、resources/config/application.yml
7、resources/application.properties(项目的resources目录下)
8、resources/application.yml