一、什么是注解?
(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
就可以注入使用了。