Spring 用注解更簡(jiǎn)單存取對(duì)象
? 上一篇文章是最原始的創(chuàng)建使用,這篇主要是講 Spring 更簡(jiǎn)單的存儲(chǔ)和讀取對(duì)象的核心是使用注解 ,也是日常生活企業(yè)用的最多的方法 “注解” 所以這篇的內(nèi)容是很重要的 ?。?!
一、更簡(jiǎn)單的存儲(chǔ) Bean 對(duì)象
1.1 前置工作
? 需要再 Spring 的配置文件中設(shè)置組件 Component 的根路徑
<?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:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置一下:bean注解掃描的根路徑(方面后面更簡(jiǎn)單存儲(chǔ)對(duì)象到spring容器)-->
<content:component-scan base-package="根路徑"></content:component-scan>
</beans>
這是很重要的一步,在 resources 包下創(chuàng)建 xml 文件來(lái)配置 Spring 信息。這里面主要加了一個(gè) component 掃描路徑代碼。
<content:component-scan base-package="組件掃描根路徑"></content:component-scan>
???問(wèn)題來(lái)了,為什么要這要設(shè)置,不能想以前添加 bean 對(duì)象嗎?
? 使用掃描包根路徑的作用:這個(gè)配置信息可以掃描你設(shè)置的根路徑以下的類,掃描是否添加了注解,把添加了注解的類存入 spring 容器里面,不加根路徑范圍全部掃描所有文件的話增加工作量效率不高吃性能。
注意只有在根路徑里面添加了注解才會(huì)被添加進(jìn) spring 里面,在根路徑意外的即使添加了注解是不會(huì)被添加進(jìn)spring 里的
? 使用掃描包路徑的優(yōu)勢(shì):
- 不用再每次注冊(cè)內(nèi)容的使用都在配置文件中添加 bean 對(duì)象,之后做項(xiàng)目的時(shí)候每次注冊(cè)bean對(duì)象會(huì)增加工作量相率正確性也不高。掃描包配置添加注解直接存入 spring 里面 更方便快捷提升效率提高性能
- 配置文件信息代碼少,不復(fù)雜,只關(guān)注根路徑就行
- 與注解搭配使用,目前企業(yè)都主要是用注解,而不是用的原始方法
二、添加注解存儲(chǔ) Spring 中(存)
2.1、類注解
2.1.1、@Controller
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public void sayHi() {
System.out.println("hi UserController");
}
}
@Controller 注解就相當(dāng)于在spring 容器里面存儲(chǔ)了 bean 對(duì)象:
<bean id="userController" class="com.yuanye.beans.userController"></bean>
@Controller 注解在spring啟動(dòng)的時(shí)候就把當(dāng)前的對(duì)象存儲(chǔ)在容器里面了。獲取對(duì)象的方法還是老三步驟:
1、得到 Spring 上下文
2、使用上下文對(duì)象獲得一個(gè) bean
3、使用 bean
具體操作步驟可以看這篇文章 Spring核心 and 創(chuàng)建使用
2.1.2、@Service
將對(duì)象存儲(chǔ)在 spring 容器中
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void sayhi() {
System.out.println("hi UserService");
}
}
@Service 注解就相當(dāng)于在spring 容器里面存儲(chǔ)了 bean 對(duì)象:
<bean id="UserService" class="com.yuanye.beans.UserService"></bean>
2.1.3、@Repository
將對(duì)象存儲(chǔ)在 spring 容器中
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
public void sayhi() {
System.out.println("hi UserRepository");
}
}
與上面的方法是一樣,不再贅述。
2.1.4、@Component
以上。
import org.springframework.stereotype.Component;
@Component
public class UserComponent {
public void sayHi() {
System.out.println("hi,UserComponent");
}
}
2.1.5、@Configuration
同上。
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfiguration {
public void sayHi() {
System.out.println("hi,UserConfiguration");
}
}
2.2、類注解的區(qū)別
???問(wèn)題:盡然他們的功能都是一樣的,那么他們究竟是有什么區(qū)別尼??
? 主要還是用來(lái)處理業(yè)務(wù)邏輯相關(guān),讓程序員一看使用某注解就明白某類在業(yè)務(wù)功能上面的用途。
- @Controller:表示業(yè)務(wù)邏輯層(首先與前端交互驗(yàn)證)
- @Service:表示服務(wù)層
- @Repository:持久層
- @Configuration:配置層
- @Component:實(shí)體類
程序的工程分層圖如下:
這張圖也詳細(xì)說(shuō)明了每個(gè)注解的作用。
2.2.1、類注解的關(guān)系
? 從源代碼來(lái)說(shuō),@Controller / @Service / @Repository / @Configuration 等注解他們都有@Component的注解。
結(jié)論:@Controller / @Service / @Repository / @Configuration 等注解他們本身屬于是 @Component 的 子類
2.3、方法注解
? 方法注解就是放在方法上面的注解
2.3.1、@Bean
目標(biāo):@Bean 將當(dāng)前方法返回的對(duì)象存入到 Spring 容器中
代碼實(shí)現(xiàn):
import com.yuanye.model.UserInfo;
import org.springframework.context.annotation.Bean;
public class UserBeans {
@Bean
public UserInfo getUser() { // 方法名就是 bean name
UserInfo userInfo = new UserInfo();// 偽代碼
userInfo.setId(1);
userInfo.setName("鳶也");
userInfo.setPassword("123456");
return userInfo;
}
}
這是在 Spring 中注冊(cè)方法,獲取這個(gè)方法還是三步驟,只不過(guò) bean name 是方法的名字
UserInfo userInfo = applicationContext.getBean("getUser",UserInfo.class);
但是這樣寫(xiě)程序會(huì)報(bào)錯(cuò):
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
???這又是為什么尼??
2.3.1.1、方法注解要配合5大類注解一起使用
答案就是方法注解要配合類注解一起使用。這是 spring 設(shè)計(jì)之初就是這樣設(shè)計(jì)的。
???為何要這樣設(shè)計(jì)???
原因是出于性能的考量:相當(dāng)于就是加一個(gè)范圍,不加范圍一個(gè)項(xiàng)目可能有成千上百個(gè)方法,如果都要掃描一遍檢查是否要將返回值存儲(chǔ)到 Spring 里面中,那么代價(jià)太大,效率低,成本高。故要 方法注解搭配類注解 來(lái)實(shí)現(xiàn)對(duì)象的托管。
正確代碼:
import com.yuanye.model.UserInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class UserBeans {
@Bean
public UserInfo getUser() { // 方法名就是 bean name
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setName("鳶也");
userInfo.setPassword("123456");
return userInfo;
}
}
2.3.1.2、@Bean 重命名
? @Bean 有一個(gè)特性 ,它可以重命名 id name。
- 可以給當(dāng)前對(duì)象指定多個(gè)名稱
- 使用多給名稱獲取的對(duì)象是同一個(gè)
- 使用了重命名不可再使用原方法名來(lái)作為 id name(原方法id name 就會(huì)得不到對(duì)象)
import com.yuanye.model.UserInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class UserBeans {
@Bean(name = {"user","userfo"}) //@Bean("user")
public UserInfo getUser() { // getUser 已經(jīng)無(wú)法再使用,得不到對(duì)象
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setName("鳶也");
userInfo.setPassword("123456");
return userInfo;
}
}
? 當(dāng)他重命名的時(shí)候,獲取 bean id 就是用的重命名,更方便操作。以上兩種寫(xiě)法都可以,如果是一個(gè)重命名參數(shù)格式 @Bean("user")
,多個(gè)重命名參數(shù)格式 @Bean(name = {"user","userfo"})
注意:使用了重命名就只能使用重命名之后 老方法獲取對(duì)象 name 不可再次使用 原方法名,因?yàn)槌绦驎?huì)報(bào)錯(cuò),就拿不到當(dāng)前對(duì)象
三、Bean(對(duì)象) 的命名
? 首先查看源碼:(一般用在類中的命名方式)通常使用在 bean id(name) 上面
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
? 在第二個(gè)if判斷語(yǔ)句中,可以看出某類如果第一個(gè)字符和第二個(gè)字符是大寫(xiě),那么就返回原來(lái)的名字就不用修改;
? 第10行代碼中,如果第一個(gè)字符是大寫(xiě),第二個(gè)字符是小寫(xiě),那么就要修改 bean 的名稱,就要把第一個(gè)字母改為小寫(xiě)即可。
四、獲取 Bean 對(duì)象 (對(duì)象裝配)
@Autowired
? 獲取 bean 對(duì)象也叫做對(duì)象裝配 ,是把對(duì)象取出來(lái)放到某個(gè)類中,有時(shí)候也叫作 對(duì)象注入 (DI:Dependency Injection)。
對(duì)象注入的方式有3種:
- 屬性注入 (企業(yè)、個(gè)人 常用)
- 構(gòu)造方法注入 (官方推薦)
- Setter 注入
注入又是怎么樣理解?
? 程序運(yùn)行期間動(dòng)態(tài)的將當(dāng)前類需要的依賴類,比如說(shuō)A類里面需要調(diào)用B的方法,那么A類就需要依賴B類,需要B對(duì)象。那么在A類里面動(dòng)態(tài)的加載B類過(guò)程就叫做“注入”。
說(shuō)白了就是在 Spring 當(dāng)中把對(duì)象拿進(jìn)當(dāng)前的對(duì)象
? 之前我們都是用的舊方法的三部曲:
1、得到 Spring 上下文
2、使用上下文對(duì)象獲得一個(gè) bean
3、使用 bean
現(xiàn)在也是可以用一個(gè)注解就搞定的。
4.1、屬性注入(企業(yè)、個(gè)人 常用)
? 使用屬性注入的方式獲得對(duì)象,獲取對(duì)象的注解為 @Autowired
,接下來(lái)我們用 @Service 注入到 @Controller的方法中
@Controller代碼實(shí)現(xiàn)如下:
@Controller
public class ArtController {
@Autowired
private ArtService artService;
public void addArt(String title, String content) {
if (title!=null && content!=null &&
!title.equals("") && !content.equals("")) {
// 滿足校驗(yàn)條件就 執(zhí)行 Service
artService.addArt(title,content);//注入了ArtService類就可以使用里面的方法了
}else {
System.out.println("添加文章失敗,前端傳遞了非法參數(shù)");
}
}
}
@Serviced代碼如下:
@Service
public class ArtService {
public void addArt(String title,String content) {
System.out.println("執(zhí)行了文章的 Service 方法:" +
""+title+" | "+content);
}
}
@Autowired
private ArtService artService;
這段代碼就是屬性注入的代碼,動(dòng)態(tài)的把 ArtService 這個(gè)對(duì)象注入進(jìn)了 ArtController 類里面。
運(yùn)行順序:先使用類型進(jìn)行查詢,如果在 Spring 中查詢到了同類型的對(duì)象就直接返回;否則使用類名稱進(jìn)行查詢,如果兩個(gè)都查詢不到,那么注入失敗,否則就是成功。屬性注入意思就說(shuō)你申請(qǐng)的屬性中類和類名都是可以在 spring 里面找的,類找不到就換成類名找 。
4.2、構(gòu)造方法注入(官方推薦)
? 當(dāng)一個(gè)類中只用一個(gè)構(gòu)造方法的時(shí)候,此時(shí)注解 @Autowired 可以省略,當(dāng)有多個(gè)構(gòu)造方法的時(shí)候 @Autowired 不可以省略。當(dāng)有多個(gè)構(gòu)造方法的時(shí)候,需要注入那個(gè)類就在構(gòu)造方法錢(qián)加上注解 @Autowired
? 這是官方推薦的方法,有點(diǎn)是他的通用性,移植性好,缺點(diǎn)是多個(gè)注入代碼會(huì)顯得比較的臃腫,當(dāng)然也可以更改設(shè)計(jì)模式讓代碼不會(huì)太臃腫。
4.3、Setter 注入
? setter注入里面的注解是千萬(wàn)不能省略的,不管是一個(gè)還是多個(gè) setter 方法都是不能省略的,這點(diǎn)與構(gòu)造方法注入要分清楚。
private ArtService artService;
@Autowired
public void setArtService(ArtService artService) {
this.artService = artService;
}
? 這里主要是創(chuàng)建一個(gè) setter 方法 來(lái)注入,大差不差與構(gòu)造方法差不多,只不過(guò) 注解 需要注意一下。
4.4、三個(gè)注入的區(qū)別對(duì)比 (面試)
1、屬性注入:優(yōu)點(diǎn)他的方式是最簡(jiǎn)單,代碼最少得;缺點(diǎn):此種寫(xiě)法只適用于 IoC 容器,非 IoC 容器不能識(shí)別。(但是企業(yè),個(gè)人經(jīng)常用這種方法)
2、構(gòu)造方法注入:是官方推薦的方案。優(yōu)點(diǎn):通用性比較好,代碼移植性高;缺點(diǎn):代碼比較多,看起來(lái)比較臃腫。(官方推薦)
3、Setter 注入:是 Spring 早期版本推薦的注入方式,通用性好,現(xiàn)在是推薦使用構(gòu)造方法注入也是默認(rèn)的注入方式。(早期版本推薦)
@Resource 另一種注入的方式
? @Resource 的功能是與 @Autowired 的功能是一致的,但也是有區(qū)別。
根據(jù)上面的圖片
- 第一個(gè)區(qū)別就是設(shè)置的參數(shù)不同,使用 @Autowired 只能設(shè)置一個(gè)屬性,而@Resource 卻可以設(shè)置多個(gè)參數(shù)。
- 他們的出生是不同的:@Autowired 來(lái)自于 Spring 框架,@Resource 來(lái)自于 JDK。
- 修飾的對(duì)象不同:@Autowired 可以用于屬性注入,構(gòu)造方法注入,Setter 注入,@Resource只能用在 屬性注入和 Setter 注入,不能用于構(gòu)造方法注入。
對(duì)于多種參數(shù)的情況,Spring 也是想了辦法解決的。
針對(duì)一個(gè)對(duì)象類型被 Spring 注入多個(gè),我們可以使用 @Autowired + @Qualifier
.
格式:
1、@Resource(name = “”)
@Resource(name = "user1")
private UserInfo userInfo;
2、@Autowired + @Qualifier
@Autowired
@Qualifier("user1")//@Qualifier(value = "user1")
private UserInfo userInfo;
總結(jié):
1、將對(duì)象存儲(chǔ)在 Spring 中:
- 使用類注解 @Controller / @Service / @Repository / @Configuration /@Component [注意他們注解之間的關(guān)系]
- 使用方法注解 @Bean 【必須和5大注解類一起使用】
2、從 Spring 中獲取對(duì)象:
- 屬性注入
- 構(gòu)造方法注入
- Setter 注入
4、注入的關(guān)鍵字:
- @Autowired
- @Resource
兩個(gè)關(guān)鍵字之間的區(qū)別:出生不同;參數(shù)設(shè)置不同,@Autowired支持一個(gè)屬性參數(shù),@Resource支持多個(gè)參數(shù)設(shè)置文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-545272.html
5、解決一個(gè)對(duì)象類型被 Spring 注入多個(gè) Bean 的方法文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-545272.html
- 使用@Resource(name = “”)
- 使用@Autowired+@Qualifier(“”)
到了這里,關(guān)于Spring 用注解更簡(jiǎn)單存取對(duì)象的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!