Java精選面試題(微信小程序):5000+道面試題和選擇題,真實面經,簡歷模版,包含Java基礎、并發、JVM、線程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架構設計、大廠真題等,在線隨時刷題!
引言
想象一下這樣的場景:用戶無需鉆研復雜的API文檔或者在繁瑣的表單間來回切換,只需通過自然語言直接與系統對話——“幫我查找所有2023年出版的圖書”、“創建一個新用戶叫張三,郵箱是zhangsan@example.com”。
這種直觀、流暢的交互方式不僅能顯著降低新用戶的學習曲線,更能大幅削減B端系統的培訓成本和實施周期,讓企業應用變得更為簡單和高效。
這正是Model Context Protocol (MCP)協議在應用層面所帶來的價值體現。
認識MCP
我這里不粘貼官方的定義,用大白話給大家解釋下:MCP就像是AI世界的"萬能適配器"。想象你有很多不同類型的服務和數據庫,每個都有自己獨特的"說話方式"。AI需要和這些服務交流時就很麻煩,因為要學習每個服務的"語言"。
MCP解決了這個問題 - 它就像一個統一的翻譯官,讓AI只需學一種"語言"就能和所有服務交流。這樣開發者不用為每個服務單獨開發連接方式,AI也能更容易獲取它需要的信息。
如果你是一個后端同學,那么應該接觸或聽說過gRPC。gRPC通過標準化的通信方式可以實現不同語言開發的服務之間進行通信,那么MCP專門為AI模型設計的"翻譯官和接口管理器",讓AI能以統一方式與各種應用或數據源交互。
我們假設開發了一個天氣服務,用戶想要查詢深圳的天氣,這里分別以傳統API方式和MCP方式進行對比:
![]()
對現有SpringBoot服務改造
這里為了演示,先準備好一個圖書管理服務,圖書實體字段如下:
import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.PastOrPresent; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDate; @Entity @Table(name = "books") @Data @AllArgsConstructor @NoArgsConstructor publicclassBook{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotBlank(message = "書名不能為空") @Column(nullable = false) private String title; @NotBlank(message = "分類不能為空") @Column(nullable = false) private String category; @NotBlank(message = "作者不能為空") @Column(nullable = false) private String author; @NotNull(message = "出版日期不能為空") @PastOrPresent(message = "出版日期不能是未來日期") @Column(nullable = false) private LocalDate publicationDate; @NotBlank(message = "ISBN編碼不能為空") @Column(nullable = false, unique = true) private String isbn; }為這個服務編寫了2個測試方法:
import com.example.entity.Book; import java.util.List; publicinterfaceBookService{ // 根據作者查詢 List findBooksByAuthor(String author); // 根據分類查詢 List findBooksByCategory(String category); }現在我們要將這個SpringBoot服務改造成MCP服務,需要以下步驟:
1.導入依賴
在pom.xml中引入相關依賴,這里提示一下anthropic的訪問需要代理,否則會提示403。
org.springframework.ai groupId>
spring-ai-core artifactId> dependency>
org.springframework.ai groupId>
spring-ai-anthropic-spring-boot-starter artifactId> dependency>
org.springframework.ai groupId>
spring-ai-mcp-server-webmvc-spring-boot-starter artifactId> dependency>
由于目前這些依賴還是預覽版本,所以在Maven中央倉庫中是找不到的,需要我們額外引入倉庫地址。
推薦程序員摸魚地址:
https://www.yoodb.com/slack-off/home.html
spring-milestones id>
Spring Milestones name>
https://repo.spring.io/milestone url>
false enabled> snapshots> repository>
spring-snapshots id>
Spring Snapshots name>
https://repo.spring.io/snapshot url>
false enabled> releases> repository>
Central Portal Snapshots name>
central-portal-snapshots id>
https://central.sonatype.com/repository/maven-snapshots/ url>
false enabled> releases>
true enabled> snapshots> repository> repositories>
關于項目中代理的配置可以參考我這段配置:
import jakarta.annotation.PostConstruct; import org.springframework.context.annotation.Configuration; @Configuration publicclassProxyConfig{ // 代理設置 privatefinal String PROXY_HOST = "127.0.0.1"; privatefinalint PROXY_PORT = 10080; @PostConstruct publicvoidsetSystemProxy(){ // 設置系統代理屬性,這會影響Spring Boot自動配置的HTTP客戶端 System.setProperty("http.proxyHost", PROXY_HOST); System.setProperty("http.proxyPort", String.valueOf(PROXY_PORT)); System.setProperty("https.proxyHost", PROXY_HOST); System.setProperty("https.proxyPort", String.valueOf(PROXY_PORT)); System.out.println("System proxy configured: http://" + PROXY_HOST + ":" + PROXY_PORT); } }2.引入配置我們的目的是將一個Spring服務改造成MCP服務,所以這里不需要進行客戶端的配置,同理,在引入依賴的時候也不用引入客戶端的依賴。
# Spring AI api-key spring.ai.anthropic.api-key=這里換成你的api-key # MCP服務端開啟 spring.ai.mcp.server.enabled=true # MCP服務端配置 spring.ai.mcp.server.name=book-management-server spring.ai.mcp.server.version=1.0.0 spring.ai.mcp.server.type=SYNC spring.ai.mcp.server.sse-message-endpoint=/mcp/message3.改造原服務方法服務的改造有兩種思路-分別是工具配置方式和函數Bean方式,這里對兩種方式都做下簡略說明:
工具配置方式在需要改造的實現類對需要改造的方法加上@Tool和@ToolParam注解分別標記方法和參數。
import com.example.entity.Book; import com.example.repository.BookRepository; import com.example.service.BookService; import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Service; import java.util.List; @Service @RequiredArgsConstructor publicclassBookServiceImpl implementsBookService{ @Resource private BookRepository bookRepository; @Override @Tool(name = "findBooksByTitle", description = "根據書名模糊查詢圖書,支持部分標題匹配") public List findBooksByTitle(@ToolParam(description = "書名關鍵詞") String title) { return bookRepository.findByTitleContaining(title); } @Override @Tool(name = "findBooksByAuthor", description = "根據作者精確查詢圖書") public List findBooksByAuthor(@ToolParam(description = "作者姓名") String author) { return bookRepository.findByAuthor(author); } @Override @Tool(name = "findBooksByCategory", description = "根據圖書分類精確查詢圖書") public List findBooksByCategory(@ToolParam(description = "圖書分類")String category) { return bookRepository.findByCategory(category); } }接著將這個實現類注冊到MCP服務器配置上即可。
import com.example.service.BookService; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.ai.tool.method.MethodToolCallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * MCP服務器配置類,負責注冊MCP工具 */ @Configuration publicclassMcpServerConfig{ /** * 注冊工具回調提供者,將BookQueryService中的@Tool方法暴露為MCP工具 * * @param bookService 圖書服務 * @return 工具回調提供者 */ @Bean public ToolCallbackProvider bookToolCallbackProvider(BookService bookService){ return MethodToolCallbackProvider.builder() .toolObjects(bookService) .build(); } }此時在聊天客戶端配置引入注冊工具即可。
import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 聊天客戶端配置類 */ @Configuration publicclassChatClientConfig{ @Autowired private ToolCallbackProvider toolCallbackProvider; /** * 配置ChatClient,注冊系統指令和工具函數 */ @Bean public ChatClient chatClient(ChatClient.Builder builder){ return builder .defaultSystem("你是一個圖書管理助手,可以幫助用戶查詢圖書信息。" + "你可以根據書名模糊查詢、根據作者查詢和根據分類查詢圖書。" + "回復時,請使用簡潔友好的語言,并將圖書信息整理為易讀的格式。") // 注冊工具方法 .defaultTools(toolCallbackProvider) .build(); } }除了上述的方式,還可以單獨聲明一個類將查詢方法作為函數Bean導出。
import com.example.entity.Book; import com.example.service.BookService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import java.util.List; import java.util.function.Function; /** * 圖書查詢服務,將查詢方法作為函數Bean導出 */ @Service publicclassBookQueryService{ @Resource private BookService bookService; /** * 根據書名查詢圖書的函數Bean */ @Bean public Function > findBooksByTitle() { return title -> bookService.findBooksByTitle(title); } /** * 根據作者查詢圖書的函數Bean */ @Bean public Function > findBooksByAuthor() { return author -> bookService.findBooksByAuthor(author); } /** * 根據分類查詢圖書的函數Bean */ @Bean public Function > findBooksByCategory() { return category -> bookService.findBooksByCategory(category); } }采用這種方式在定義AI聊天客戶端的時候需要顯式地聲明。
import org.springframework.ai.chat.client.ChatClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 聊天客戶端配置類 */ @Configuration publicclassChatClientConfig{ /** * 配置ChatClient,注冊系統指令和工具函數 */ @Bean public ChatClient chatClient(ChatClient.Builder builder){ return builder .defaultSystem("你是一個圖書管理助手,可以幫助用戶查詢圖書信息。" + "你可以根據書名模糊查詢、根據作者查詢和根據分類查詢圖書。" + "回復時,請使用簡潔友好的語言,并將圖書信息整理為易讀的格式。") // 注冊工具方法,這里使用方法名稱來引用Spring上下文中的函數Bean .defaultTools( "findBooksByTitle", "findBooksByAuthor", "findBooksByCategory" ) .build(); } }4.接口測試完成了服務開發后,我們就可以聲明一個控制器對外暴露進行調用。
import com.example.model.ChatRequest; import com.example.model.ChatResponse; import jakarta.annotation.Resource; import org.springframework.ai.chat.client.ChatClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; /** * 聊天控制器,處理AI聊天請求 */ @RestController @RequestMapping("/api/chat") publicclassChatController{ @Resource private ChatClient chatClient; /** * 處理聊天請求,使用AI和MCP工具進行響應 * * @param request 聊天請求 * @return 包含AI回復的響應 */ @PostMapping public ResponseEntity chat(@RequestBody ChatRequest request){ try { // 創建用戶消息 String userMessage = request.getMessage(); // 使用流式API調用聊天 String content = chatClient.prompt() .user(userMessage) .call() .content(); return ResponseEntity.ok(new ChatResponse(content)); } catch (Exception e) { e.printStackTrace(); return ResponseEntity.ok(new ChatResponse("處理請求時出錯: " + e.getMessage())); } } }為了方便測試,我們開發一個數據初始化器,通過實現CommandLineRunner接口,它會在我們的應用程序啟動時自動向數據庫中加載這些測試數據。
import com.example.entity.Book; import com.example.repository.BookRepository; import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.util.Arrays; import java.util.List; @Component @RequiredArgsConstructor publicclassDataInitializer implementsCommandLineRunner{ @Resource private BookRepository bookRepository; @Override publicvoidrun(String... args)throws Exception { // 準備示例數據 List sampleBooks = Arrays.asList( new Book(null, "Spring實戰(第6版)", "編程", "Craig Walls", LocalDate.of(2022, 1, 15), "9787115582247"), new Book(null, "深入理解Java虛擬機", "編程", "周志明", LocalDate.of(2019, 12, 1), "9787111641247"), new Book(null, "Java編程思想(第4版)", "編程", "Bruce Eckel", LocalDate.of(2007, 6, 1), "9787111213826"), new Book(null, "算法(第4版)", "計算機科學", "Robert Sedgewick", LocalDate.of(2012, 10, 1), "9787115293800"), new Book(null, "云原生架構", "架構設計", "張三", LocalDate.of(2023, 3, 15), "9781234567890"), new Book(null, "微服務設計模式", "架構設計", "張三", LocalDate.of(2021, 8, 20), "9789876543210"), new Book(null, "領域驅動設計", "架構設計", "Eric Evans", LocalDate.of(2010, 4, 10), "9787111214748"), new Book(null, "高性能MySQL", "數據庫", "Baron Schwartz", LocalDate.of(2013, 5, 25), "9787111464747"), new Book(null, "Redis實戰", "數據庫", "Josiah L. Carlson", LocalDate.of(2015, 9, 30), "9787115419378"), new Book(null, "深入淺出Docker", "容器技術", "李四", LocalDate.of(2022, 11, 20), "9787123456789") ); // 保存示例數據 bookRepository.saveAll(sampleBooks); System.out.println("數據初始化完成,共加載 " + sampleBooks.size() + " 本圖書"); } }接下來我們通過請求接口進行如下測試:
![]()
可以看到此時返回結果是數據庫中的測試數據內容。這里是根據用戶輸入的問題,大模型會判斷我們開放的工具方法中是否有匹配的,如果有則進行調用并返回。
小結
通過Spring Boot與MCP的整合,我們輕松實現了傳統CRUD系統到智能AI助手的轉變。MCP作為AI與服務之間的橋梁,極大簡化了集成工作。未來隨著MCP生態發展,"對話即服務"將可能成為應用的開發范式,讓復雜系統變得更加易用。
代碼示例:
https://github.com/Pitayafruits/spring-boot-mcp-demo
來源:https://juejin.cn/post/7483454392979570700
公眾號“Java精選”所發表內容注明來源的,版權歸原出處所有(無法查證版權的或者未注明出處的均來自網絡,系轉載,轉載的目的在于傳遞更多信息,版權屬于原作者。如有侵權,請聯系,筆者會第一時間刪除處理!
最近有很多人問,有沒有讀者或者摸魚交流群!加入方式很簡單,公眾號Java精選,回復“加群”,即可入群!
文章有幫助的話,點在看,轉發吧!
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.