一、什么是注解?
(1)注解的定义
注解(Annotation)是 Java 代码中的一种特殊标记,用于在程序运行或编译时提供元信息。
格式:
@注解名(属性名=属性值, 属性名=属性值...)
(2)注解的使用位置
注解可以作用在:
位置 | 示例 |
---|---|
类上 | @Component 、@Controller 等 |
方法上 | @PostMapping 、@Bean 等 |
属性上 | @Autowired 、@Value 等 |
(3)为什么要用注解?
以前 Spring 使用 XML 管理 Bean(如 <bean>
标签),太繁琐。
使用注解的目的就是:
-
减少繁琐 XML 配置
-
提高开发效率
-
实现“零 XML”开发(尤其在 Spring Boot 中)
二、Spring 提供的用于创建 Bean 的注解
Spring 提供四个核心注解来创建 Bean:
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
上面四个注解功能是一样的,都可以用来创建 bean 实例。
第一步,引入AOP依赖
<!-- Spring AOP --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.34</version></dependency>
第二步,在配置文件中,开启组件扫描
要想让这些注解生效,必须启用 组件扫描,告诉 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"xmlns:util="http://www.springframework.org/schema/util"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 开启组件扫描 --><context:component-scan base-package="createBean"/>
1、添加context命名空间
2、开启组件扫描
第三步,创建类,在类上添加注解。
2-1、@Component
-
通用组件注解,表示这个类会被 Spring 容器管理。
-
最基本的注解,其他三个都是它的“语义化子类”。
这四个注解效果都是一样的,都能实现创建bean,只是语义不同!
@Component
public class UserService {// ...
}
2-2、@Service
-
用于 业务逻辑层(Service)
-
语义更清晰,等价于
@Component
@Service
public class OrderService {// 业务处理逻辑
}
2-3、@Controller
-
用于 控制层(Controller)
-
和 Spring MVC 一起使用,处理前端请求
@Controller
public class UserController {@RequestMapping("/hello")public String hello() {return "hello.jsp";}
}
2-4、@Repository
-
用于 数据访问层(DAO)
-
Spring 会对其进行 异常转换(把 JDBC 异常转换为 Spring 的统一异常)
@Repository
public class UserDao {// 数据访问逻辑
}
2-5、总结:这四个注解有什么关系?
注解 | 说明 | 本质上就是 @Component |
---|---|---|
@Component | 通用组件,推荐基础类使用 | ✅ |
@Service | 用于 Service 层 | ✅(语义化) |
@Controller | 用于 Web 层控制器 | ✅(语义化) |
@Repository | 用于 DAO 层 | ✅(附带异常转换功能) |
2-6、精准控制扫描范围
1、include-filter
2、exclude-filter
三、如何让 Spring 识别这些注解?
要想让这些注解生效,必须启用 组件扫描,告诉 Spring 去哪些包下扫描这些类。
3-1、XML 方式启用注解扫描:
<context:component-scan base-package="com.example"/>
3-2、Java 配置方式:(完全注解开发)
@Configuration
@ComponentScan("com.example")
public class AppConfig {
}
背景:为什么有这段代码?
这是 Spring 在**使用注解配置(纯 Java 配置)**时,替代 XML 配置的一种方式,用来告诉 Spring:
“这是一个 Java 配置类,它会负责创建和管理 Spring 容器中的 Bean。”
此时,可以用配置类,完全替代xml配置文件,实现完全注解开发!
1、@Configuration
注解详解
🟡 作用:
@Configuration
用于声明一个类是 配置类(Configuration Class),等价于以前的
applicationContext.xml
或beans.xml
文件。
🟢 本质:
@Configuration
本质上是一个 @Component
,因此它本身也会被 Spring 管理为一个 Bean。
-
会告诉 Spring:“这里面的方法可以用来生成 Bean。”
-
配合
@Bean
注解使用最常见(手动注册 Bean)
🧠 举例:
@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserService(); // 相当于 <bean id="userService" class="..."/>}
}
2、@ComponentScan("com.example")
注解详解
🟡 作用:
告诉 Spring 自动扫描指定包及其子包中的所有注解类(比如 @Component
、@Service
、@Controller
、@Repository
),并将它们注册为 Spring 容器中的 Bean。
🟢 类似于 XML 中的配置:
<context:component-scan base-package="com.example"/>
🧠 举例:
@ComponentScan("com.example")
表示扫描 com.example
这个包及其子包中的类。
只要类上有下面这些注解之一:
-
@Component
-
@Service
-
@Controller
-
@Repository
Spring 就会自动创建这些类的实例并放入 IoC 容器。
3、完整代码解释
@Configuration // 声明这是一个配置类,代替 XML 配置
@ComponentScan("com.example") // 扫描 com.example 包下的所有注解 Bean
public class AppConfig {// 此类可以写 @Bean 方法,也可以不写(只做组件扫描)
}
4、使用方式:怎么让它生效?
你需要创建一个 Spring 容器,并传入这个配置类:
// 使用注解方式创建容器(非 XML)
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取 Bean
UserService userService = context.getBean(UserService.class);
userService.sayHello();
5、进阶补充
(1)、多个包扫描,数组形式!
@ComponentScan(basePackages = {"com.example", "com.other"})
(2)、精准控制扫描范围(排除特定类)
@ComponentScan(basePackages = "com.example",excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)
)
6、小结对比(XML vs 注解方式)
功能 | XML 配置 | 注解配置(现代 Spring 推荐) |
---|---|---|
声明配置文件 | <beans> | @Configuration |
声明组件扫描 | <context:component-scan> | @ComponentScan |
注册 Bean | <bean> | @Bean |
7、示意图结构:
com.example
├── AppConfig.java // @Configuration + @ComponentScan
├── controller
│ └── HelloController.java // @Controller
├── service
│ └── HelloService.java // @Service
└── dao└── UserDao.java // @Repository
四、基于注解方式实现属性的注入(Dependency Injection: DI)
Spring 提供多种注解方式来将对象之间的依赖关系注入到类中,最常见的是:
(1)@Autowired
(2)@Qualifier
(3)@Resource
(来自 JSR-250,Java 标准)
4-1、@Autowired —— 按类型注入
作用:自动根据类型(byType)在 Spring 容器中查找匹配的 Bean 并注入。
第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解;
第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解
示例:
@Component
public class UserController {@Autowiredprivate UserService userService; // 自动注入 UserService 类型的 Bean
}
如果容器中只有一个
UserService
类型的 Bean,就能正常注入。
支持的注入位置:
属性注入(推荐)
构造函数注入
Setter方法注入
1、属性注入(常用):
@Autowired
private UserService userService;
2、构造函数注入:
@Autowired
public UserController(UserService userService) {this.userService = userService;
}
3、Setter注入:
@Autowired
public void setUserService(UserService userService) {this.userService = userService;
}
❗注意:
默认 按类型 注入(byType)
如果找到多个相同类型的 Bean → 会报错(
NoUniqueBeanDefinitionException
)
4、可选注入
默认情况下,当我们标记了一个@Autowired
后,Spring如果没有找到对应类型的Bean,它会抛出NoSuchBeanDefinitionException
异常。
可以给@Autowired
增加一个required = false
的参数:
@Component
public class MailService {@Autowired(required = false)ZoneId zoneId = ZoneId.systemDefault();...
}
这个参数告诉Spring容器,如果找到一个类型为ZoneId
的Bean,就注入,如果找不到,就忽略。
这种方式非常适合有定义就使用定义,没有就使用默认值的情况。
4-2、@Qualifier —— 配合 @Autowired 精确指定注入哪一个 Bean(按名字)
当容器中有多个相同类型的 Bean 时,用 @Qualifier("beanName")
指定注入哪个。
示例:
@Component("userServiceA")
public class UserServiceA implements UserService {}@Component("userServiceB")
public class UserServiceB implements UserService {}@Component
public class UserController {@Autowired@Qualifier("userServiceA")private UserService userService; // 明确注入 userServiceA
}
【注意】:
@Qualifier
只能和@Autowired
搭配使用。
4-3、@Resource —— 按名字注入(来自 JSR-250)
来自 Java 标准规范(javax.annotation.Resource),也被 Spring 支持。
默认注入规则:
-
先按 名字(byName)找 Bean;
-
如果找不到,再按类型(byType)找。
示例:
@Resource(name = "userService")
private UserService userService;
如果没写 name
属性:
Spring 默认使用变量名作为 Bean 名称:
@Resource
private UserService userService; // 默认去找名为 "userService" 的 Bean
4-4、三者对比总结:
特性 | @Autowired | @Qualifier | @Resource |
---|---|---|---|
来自包 | Spring(org.springframework ) | Spring | JDK(javax.annotation ) |
注入方式 | 默认按类型(byType) | 搭配 @Autowired 使用,按名称 | 默认按名称(byName),找不到再按类型 |
支持位置 | 属性、构造器、方法 | 搭配 @Autowired 使用 | 属性、方法(不推荐构造器) |
是否必须 | 默认必须,配合 @Autowired(required = false) 可设为非必须 | - | 默认必须,可搭配 @Resource(name="...") 使用 |
推荐使用方式(Spring 开发建议)
-
单一 Bean 时:直接用
@Autowired
-
多个实现类时:用
@Autowired + @Qualifier
-
需要兼容 JDK 标准规范时:用
@Resource(这不是spring官方的注解,是javax里面的)
4-5、例子完整演示
@Service("userServiceA")
public class UserServiceA implements UserService {}@Service("userServiceB")
public class UserServiceB implements UserService {}@Controller
public class UserController {// 推荐使用方式一@Autowired@Qualifier("userServiceA")private UserService userService;// 或者使用标准注解方式// @Resource(name = "userServiceB")// private UserService userService;
}
4-6、@Value注解
以上的三个注解,都是属性类型是对象的注解,当属性类型是普通数据类型的时候,可以使用@Value注解。
除此以外,@Value还可以注入:
字面量(常量、字符串等)
配置文件中的值(
.properties
或.yml
中)SpEL 表达式(Spring Expression Language)
当然可以!下面是对 @Value
注解的详细讲解,帮助你全面理解它的作用、用法和使用场景:
1、常见使用场景
(1)注入常量值
@Value("Hello Spring")
private String msg;
(2)注入配置文件中的值(最常见)
假设有 application.properties
文件:
app.name=SmartCampus
app.version=1.0.2
然后在 Java 类中使用:
@Component
public class AppInfo {@Value("${app.name}")private String appName;@Value("${app.version}")private String version;
}
Spring 会自动从配置文件中找到
app.name
对应的值并注入。
(3)、使用条件
.properties
文件必须加载进 Spring 容器中!!!
如果你使用的是 Spring Boot → 它自动加载了 application.properties
,不需要额外配置。
但如果你是传统 Spring XML 项目:
<context:property-placeholder location="classpath:application.properties"/>
【回顾】:
这是spring加载外部配置文件的方式!
(4)、支持 SpEL 表达式(计算、引用 Bean 等)
示例 1:表达式计算
@Value("#{5 * 2}")
private int result; // result = 10
示例 2:引用其他 Bean 的属性
@Value("#{userService.name}")
private String userName;
注意观察#{}
这种注入语法,它和${key}
不同的是,#{}
表示从JavaBean读取属性。
示例:"#{smtpConfig.host}"
的意思是,从名称为smtpConfig
的Bean读取host
属性,即调用getHost()
方法。
使用一个独立的JavaBean持有所有属性,然后在其他Bean中以#{bean.property}
注入的好处是,多个Bean都可以引用同一个Bean的某个属性。
(5)、也可以用在方法或构造器参数上
@Component
public class Server {private int port;public Server(@Value("${server.port}") int port) {this.port = port;}
}
(6)、@Value 注入数组、集合
示例:
app.languages=Java,Python,R
@Value("#{'${app.languages}'.split(',')}")
private List<String> languages;
(7)、小结
注解 | 用途 |
---|---|
@Value | 注入属性值(字面量、配置、SpEL) |
${} | 取配置文件中的值 |
#{} | SpEL 表达式(计算、引用等) |
五、创建第三方Bean
Spring 中一个非常典型的场景:
❓如何将一个没有使用 @Component 注解的第三方类(如
HikariDataSource
)交给 Spring IoC 容器管理?
因为第三方类你无法直接修改源代码(不能加 @Component
),所以不能自动扫描识别。我们需要用 显式注册的方式 告诉 Spring 去创建并管理这个 Bean。
解决方案:使用
@Configuration
+@Bean
创建第三方 Bean。即:
我们自己在
@Configuration
类中编写一个Java方法创建并返回它,注意给方法标记一个@Bean
注解:
你可以在一个 Java 配置类中,手动创建并配置 HikariDataSource
,然后交给 Spring 容器管理。
示例代码:创建并注入 HikariDataSource
步骤 1:添加依赖(Spring + HikariCP)
Maven 依赖示例:
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>5.1.0</version>
</dependency>
步骤 2:配置文件 application.properties
db.url=jdbc:mysql://localhost:3306/test
db.username=root
db.password=123456
步骤 3:Java 配置类 AppConfig.java
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {@Value("${db.url}")private String jdbcUrl;@Value("${db.username}")private String username;@Value("${db.password}")private String password;// 手动创建 HikariDataSource@Beanpublic HikariDataSource dataSource() {HikariDataSource ds = new HikariDataSource();ds.setJdbcUrl(jdbcUrl);ds.setUsername(username);ds.setPassword(password);return ds;}// 如果你有 UserService 也可以在这里注入@Beanpublic UserService userService(HikariDataSource dataSource) {return new UserService(dataSource);}
}
【注意】:
Spring对标记为
@Bean
的方法只调用一次,因此返回的Bean仍然是单例。
使用方式:
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = context.getBean(UserService.class);
userService.doSomething();
小结:创建第三方 Bean 的三种常见方法
方法 | 使用场景 | 示例 |
---|---|---|
@Bean 方法 | 最推荐方式,灵活、清晰、能配置参数 | @Bean public HikariDataSource dataSource() { ... } |
XML 配置 | 传统 Spring 项目可用 | <bean class="com.zaxxer.hikari.HikariDataSource" .../> |
总结:
如果我们想给
UserService
注入一个来自第三方包(如HikariDataSource
)的 Bean:
-
使用
@Configuration
类 -
编写
@Bean
方法创建并配置HikariDataSource
-
然后通过构造器或
@Autowired
注入到其他组件中
【注意】:
在 Spring Boot 项目中,如果你想将一个第三方类(比如
HikariDataSource
)注入到自己的类中,通常你只需要:1、添加maven依赖
2、使用
@Autowired
就可以注入使用了。