溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework

發(fā)布時間:2020-07-29 18:17:52 來源:網(wǎng)絡(luò) 閱讀:776 作者:匆匆的那年 欄目:軟件技術(shù)

一、架構(gòu)和組件關(guān)系圖

Spring 5的架構(gòu)圖如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


各組件之間的依賴圖如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


Spring520 個組件(1300多個文件),這些組件被分別整合在核心容器(Core Container)、AOPAspect Oriented Programming)和設(shè)備支持(Instrmentation)、數(shù)據(jù)訪問及集成(Data Access/Integeration)、Web、報文發(fā)送(Messaging)、Test中。

1、核心容器

spring-beans、spring-corespring-context spring-expressionSpring Expression Language, SpEL)組成,4個組件。

?

spring-beans ?spring-core 模塊是?Spring 框架的核心模塊,包含了控制反轉(zhuǎn)(Inversion of

Control, IOC)和依賴注入(Dependency Injection, DI)。

其中,BeanFactory 接口是 Spring 框架中的核心接口,它是工廠模式的具體實現(xiàn)。BeanFactory 使用控制反轉(zhuǎn)對應(yīng)用程序的配置和依賴性規(guī)范與實際的應(yīng)用程序代碼進行了分離。但 BeanFactory 容器實例化后并不會自動實例化 Bean,只有當(dāng) Bean被使用時 BeanFactory 容器才會對該 Bean 進行實例化與依賴關(guān)系的裝配。

?

spring-context 模塊構(gòu)架于核心模塊之上,他擴展了?BeanFactory,為她添加了?Bean 生命周期控制、框架事件體系以及資源加載透明化等功能。此外該模塊還提供了許多企業(yè)級支持,如郵件訪問、遠(yuǎn)程訪問、任務(wù)調(diào)度等,ApplicationContext 是該模塊的核心接口,她是 BeanFactory 的超類,與BeanFactory 不同,ApplicationContext 容器實例化后會自動對所有的單實例 Bean 進行實例化與依賴關(guān)系的裝配,使之處于待用狀態(tài)。

?

spring-expression 模塊是統(tǒng)一表達式語言(EL)的擴展模塊,可以查詢、管理運行中的對象,?

同時也方便的可以調(diào)用對象方法、操作數(shù)組、集合等。它的語法類似于傳統(tǒng) EL,但提供了額外的功能,最出色的要數(shù)函數(shù)調(diào)用和簡單字符串的模板函數(shù)。這種語言的特性是基于 Spring 產(chǎn)品的需求而設(shè)計,他可以非常方便地同 Spring IOC 進行交互。

?

2、AOP 和設(shè)備支持

spring-aop、spring-aspects spring-instrument組成,3個組件。

?

spring-aop ?Spring 的另一個核心模塊,是?AOP 主要的實現(xiàn)模塊。作為繼?OOP 后,對程序員影響最大的編程思想之一,AOP 極大地開拓了人們對于編程的思路。在 Spring 中,他是以 JVM 的動態(tài)代理技術(shù)為基礎(chǔ),然后設(shè)計出了一系列的 AOP 橫切實現(xiàn),比如前置通知、返回通知、異常通知等,同時, Pointcut 接口來匹配切入點,可以使用現(xiàn)有的切入點來設(shè)計橫切面,也可以擴展相關(guān)方法根據(jù)需求進行切入。

?

spring-aspects 模塊集成自?AspectJ 框架,主要是為?Spring AOP 提供多種?AOP 實現(xiàn)方法。?

?

spring-instrument 模塊是基于 JAVA SE 中的“ava.lang.instrument”進行設(shè)計的,應(yīng)該算是

AOP 的一個支援模塊,主要作用是在 JVM 啟用時,生成一個代理類,程序員通過代理類在運行時修改類的字節(jié),從而改變一個類的功能,實現(xiàn) AOP 的功能。

?

3、數(shù)據(jù)訪問及集成

spring-jdbc、spring-tx、spring-orm、spring-jms spring-oxm組成,5個組件。

?

spring-jdbc 模塊是?Spring 提供的?JDBC 抽象框架的主要實現(xiàn)模塊,用于簡化?Spring JDBC。主要是提供 JDBC 模板方式、關(guān)系數(shù)據(jù)庫對象化方式、SimpleJdbc 方式、事務(wù)管理來簡化 JDBC編程,主要實現(xiàn)類是 JdbcTemplate、SimpleJdbcTemplate 以及 NamedParameterJdbcTemplate

?

spring-tx模塊是?Spring JDBC 事務(wù)控制實現(xiàn)模塊。使用?Spring 框架,它對事務(wù)做了很好的封裝,?通過它的 AOP 配置,可以靈活的配置在任何一層;但是在很多的需求和應(yīng)用,直接使用 JDBC 事務(wù)控制還是有其優(yōu)勢的。其實,事務(wù)是以業(yè)務(wù)邏輯為基礎(chǔ)的;一個完整的業(yè)務(wù)應(yīng)該對應(yīng)業(yè)務(wù)層里的一個方法; 如果業(yè)務(wù)操作失敗,則整個事務(wù)回滾;所以,事務(wù)控制是絕對應(yīng)該放在業(yè)務(wù)層的;但是,持久層的設(shè)計則應(yīng)該遵循一個很重要的原則:保證操作的原子性,即持久層里的每個方法都應(yīng)該是不可以分割的。所以,在使用 Spring JDBC 事務(wù)控制時,應(yīng)該注意其特殊性。

?

spring-orm 模塊是?ORM 框架支持模塊,主要集成?Hibernate, Java Persistence API (JPA) Java Data Objects (JDO) 用于資源管理、數(shù)據(jù)訪問對象(DAO)的實現(xiàn)和事務(wù)策略。

?

spring-jms 模塊(Java Messaging Service)能夠發(fā)送和接受信息,自?Spring Framework 4.1

以后,他還提供了對 spring-messaging 模塊的支撐。

?

spring-oxm 模塊主要提供一個抽象層以支撐?OXMOXM ?Object-to-XML-Mapping 的縮寫,它是一個?O/M-mapper,將?java 對象映射成?XML 數(shù)據(jù),或者將?XML 數(shù)據(jù)映射成?java 對象),例如:JAXB,Castor, XMLBeans, JiBX ?XStream 等。

?

4Web

spring-web、spring-webmvc、spring-websocket spring-webflux 組成,4個組件。

?

spring-web 模塊為?Spring 提供了最基礎(chǔ)?Web 支持,主要建立于核心容器之上,通過?Servlet ? Listeners 來初始化 IOC 容器,也包含一些與 Web 相關(guān)的支持。

?

spring-webmvc模塊是一個的Web-Servlet模塊,實現(xiàn)了Spring MVC model-view-Controller)的 Web 應(yīng)用。

?

spring-websocket 模塊主要是與?Web 前端的全雙工通訊的協(xié)議。

?

spring-webflux 是一個新的非堵塞函數(shù)式?Reactive Web 框架,可以用來建立異步的,非阻塞,事件驅(qū)動的服務(wù),并且擴展性非常好。

?

5、報文發(fā)送

包括spring-messaging 1個組件。

?

spring-messaging是從?Spring4 開始新加入的一個模塊,主要職責(zé)是為?Spring 框架集成一些基礎(chǔ)的報文傳送應(yīng)用。

?

6、Test

包含spring-test,1個組件。

spring-test 模塊主要為測試提供支持的,畢竟在不需要發(fā)布(程序)到你的應(yīng)用服務(wù)器或者連接到其他企業(yè)設(shè)施的情況下能夠執(zhí)行一些集成測試或者其他測試對于任何企業(yè)都是非常重要的。


二、 Spring Bean基礎(chǔ)

Bean配置信息定義了Bean的實現(xiàn)及依賴關(guān)系,Spring容器根據(jù)各種形式的Bean配置信息在容器內(nèi)部建立Bean定義注冊表,然后根據(jù)注冊表加載、實例化Bean,并建立BeanBean的依賴關(guān)系,最后將這些準(zhǔn)備就緒的Bean放到Bean緩存池中,以供外層的應(yīng)用程序進行調(diào)用。下圖是一張老圖:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


1、bean配置

bean配置有三種方法:

基于xml配置Bean

使用注解定義Bean

基于java類提供Bean定義信息

?

1.1 基于xml配置Bean

?對于基于XML的配置,Spring 2.0以后使用Schema的格式,使得不同類型的配置擁有了自己的命名空間,是配置文件更具擴展性。

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


默認(rèn)命名空間:它沒有空間名,用于Spring Bean的定義;

xsi命名空間:這個命名空間用于為每個文檔中命名空間指定相應(yīng)的Schema樣式文件,是標(biāo)準(zhǔn)組織定義的標(biāo)準(zhǔn)命名空間;

aop命名空間:這個命名空間是Spring配置AOP的命名空間,是用戶自定義的命名空間。

?

命名空間的定義分為兩個步驟:第一步指定命名空間的名稱;第二步指定命名空間的Schema文檔樣式文件的位置,用空格或回車換行進行分分隔。

?

1.1.1 Bean基本配置

Spring容器的配置文件中定義一個簡要Bean的配置片段如下所示:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


一般情況下,Spring IOC容器中的一個Bean即對應(yīng)配置文件中的一個<bean>,這種鏡像對應(yīng)關(guān)系應(yīng)該容易理解。其中id為這個Bean的名稱,通過容器的getBean("foo")即可獲取對應(yīng)的Bean,在容器中起到定位查找的作用,是外部程序和Spring IOC容器進行交互的橋梁。class屬性指定了Bean對應(yīng)的實現(xiàn)類。

下面是基于XML的配置文件定義了兩個簡單的Bean

<?xml version="1.0" encoding="UTF-8" ?>

<beans ??xmlns="http://www.springframework.org/schema/beans"

?????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

?????????xsi:schemaLocation="http://www.springframework.org/schema/beans

?????????http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

?????<bean id="car" name="#car1" class="com.baobaotao.simple.Car"></bean> ?

?????<bean id="boss" class="com.baobaotao.simple.Boss"></bean>

</beans>

1.1.2 依賴注入

屬性注入

構(gòu)造函數(shù)注入

工廠方式注入

1.2 使用注解定義Bean

我們知道,Spring容器成功啟動的三大要件分別是:Bean定義信息、Bean實現(xiàn)類以及Spring本身。如果采用基于XML的配置,Bean定義信息和Bean實現(xiàn)類本身是分離的,而采用基于注解的配置方式時,Bean定義信息即通過在Bean實現(xiàn)類上標(biāo)注注解實現(xiàn)。

下面是使用注解定義一個DAOBean

package com.baobaotao.anno;

?

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Repository;

//①通過Repository定義一個DAOBean

?

@Component("userDao")

public class UserDao {

}

處,我們使用@Component注解在UserDao類聲明處對類進行標(biāo)注,它可以被Spring容器識別,Spring容器自動將POJO轉(zhuǎn)換為容器管理的Bean。

它和以下的XML配置是等效的:

<bean id="userDao"?class="com.baobaotao.anno.UserDao"/>

除了@Component以外,Spring提供了3個功能基本和@Component等效的注解,它們分別用于對DAO、ServiceWeb層的Controller進行注解,所以也稱這些注解為Bean的衍型注解:(類似于xml文件中定義Bean<bean id=" " class=" "/>

@Repository:用于對DAO實現(xiàn)類進行標(biāo)注;

@Service:用于對Service實現(xiàn)類進行標(biāo)注;

@Controller:用于對Controller實現(xiàn)類進行標(biāo)注;

之所以要在@Component之外提供這三個特殊的注解,是為了讓注解類本身的用途清晰化,此外Spring將賦予它們一些特殊的功能。

1.2.1 使用注解配置信息啟動spring容器

Spring提供了一個context的命名空間,它提供了通過掃描類包以應(yīng)用注解定義Bean的方式:

<?xml version="1.0" encoding="UTF-8" ?>

<!--①聲明context的命名空間-->

<beans xmlns="http://www.springframework.org/schema/beans"

????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

????xmlns:context="http://www.springframework.org/schema/context"

????xsi:schemaLocation="http://www.springframework.org/schema/beans

?????????http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

?????????http://www.springframework.org/schema/context

?????????http://www.springframework.org/schema/context/spring-context-3.0.xsd"

?????????>

????<!--②掃描類包以應(yīng)用注解定義的Bean-->

???<context:component-scan base-package="com.baobaotao.anno"/>

???<bean class="com.baobaotao.anno.LogonService"></bean>

???<!-- context:component-scan base-package="com.baobaotao" resource-pattern="anno/*.class"/ -->

???<!-- context:component-scan base-package="com.baobaotao">

???????<context:include-filter type="regex" expression="com\.baobaotao\.anno.*Dao"/>

???????<context:include-filter type="regex" expression="com\.baobaotao\.anno.*Service"/>

???????<context:exclude-filter type="aspectj" expression="com.baobaotao..*Controller+"/>

???</context:component-scan -->

</beans>

處聲明context命名空間,在處即可通過context命名空間的component-scanbase-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包里的所有類,并從類的注解信息中獲取Bean的定義信息。

如果僅希望掃描特定的類而非基包下的所有類,你們可以使用resource-pattern屬性過濾特定的類,如下所示:

<?context:component-scan base-package="com.baobaotao"?resource-pattern="anno/*.class"/ >

這里我們將基類包設(shè)置為com.baobaotao,默認(rèn)情況下resource-pattern屬性的值為"**/*.class",即基類包里的所有類。這里我們設(shè)置為"anno/*.class",Spring僅會掃描基包里anno子包中的類。

1.3 基于java類提供Bean定義

在普通的POJO類中只要標(biāo)注@Configuration注解,就可以為spring容器提供Bean定義的信息了,每個標(biāo)注了@Bean的類方法都相當(dāng)于提供了一個Bean的定義信息。

package com.baobaotao.conf;

?

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

//①將一個POJO標(biāo)注為定義Bean的配置類

@Configuration

public class AppConf {

????????//②以下兩個方法定義了兩個Bean,以提供了Bean的實例化邏輯

????@Bean

????public UserDao userDao(){

???????return new UserDao(); ???

????}

????

????@Bean

????public LogDao logDao(){

????????return new LogDao();

????}

????//③定義了logonServiceBean

????@Bean

????public LogonService logonService(){

????????LogonService logonService = new LogonService();

????????????????//④將②和③處定義的Bean注入到LogonService Bean

????????logonService.setLogDao(logDao());

????????logonService.setUserDao(userDao());

????????return logonService;

????}

}

處在APPConf類的定義處標(biāo)注了@Configuration注解,說明這個類可用于為Spring提供Bean的定義信息。類的方法處可以標(biāo)注@Bean注解,Bean的類型由方法返回值類型決定,名稱默認(rèn)和方法名相同,也可以通過入?yún)@示指定Bean名稱,如@Bean(name="userDao").直接在@Bean所標(biāo)注的方法中提供Bean的實例化邏輯。

userDao()logDao()方法定義了一個UserDao和一個LogDaoBean,它們的Bean名稱分別是userDaologDao。在處,又定義了一個logonService Bean,并且在處注入處所定義的兩個Bean

因此,以上的配置和以下XML配置時等效的:

<bean id="userDao"?class="com.baobaotao.anno.UserDao"/>

<bean id="logDao"?class="com.baobaotao.anno.LogDao"/>

<bean id="logService"?class="com.baobaotao.conf.LogonService"

????p:logDao-ref="logDao"?p:userDao-ref="userDao"/>

基于java類的配置方式和基于XML或基于注解的配置方式相比,前者通過代碼的方式更加靈活地實現(xiàn)了Bean的實例化及Bean之間的裝配,但后面兩者都是通過配置聲明的方式,在靈活性上要稍遜一些,但是配置上要更簡單一些。

2 Bean注入

Bean注入的方式有兩種,一種是在XML中配置,此時分別有屬性注入、構(gòu)造函數(shù)注入和工廠方法注入;另一種則是使用注解的方式注入?@Autowired,@Resource,@Required。

2.1 xml文件中配置依賴注入

2.1.1 屬性注入

屬性注入即通過setXxx()方法注入Bean的屬性值或依賴對象,由于屬性注入方式具有可選擇性和靈活性高的優(yōu)點,因此屬性注入是實際應(yīng)用中最常采用的注入方式。

屬性注入要求Bean提供一個默認(rèn)的構(gòu)造函數(shù),并為需要注入的屬性提供對應(yīng)的Setter方法。Spring先調(diào)用Bean的默認(rèn)構(gòu)造函數(shù)實例化Bean對象,然后通過反射的方式調(diào)用Setter方法注入屬性值。

package com.baobaotao.anno;

?

import org.springframework.beans.factory.BeanNameAware;

?

public class LogonService implements BeanNameAware{

?

????private LogDao logDao;

?

????private UserDao userDao;

?

????public void setUserDao(UserDao userDao) {

????????this.userDao = userDao;

????}

?

????public void setLogDao(LogDao logDao) {

????????this.logDao = logDao;

????}

????

????public LogDao getLogDao() {

????????return logDao;

????}

????public UserDao getUserDao() {

????????return userDao;

????}

????

????public void setBeanName(String beanName) {

????????System.out.println("beanName:"+beanName); ???????

????}

????

????public void initMethod1(){

????????System.out.println("initMethod1");

????}

????public void initMethod2(){

????????System.out.println("initMethod2");

????}

}

?

bean.xml配置

<?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:context="http://www.springframework.org/schema/context"

????xsi:schemaLocation="http://www.springframework.org/schema/beans

?????????http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

?????????http://www.springframework.org/schema/context

?????????http://www.springframework.org/schema/context/spring-context-3.0.xsd"

???????default-autowire="byName"

?????????>

????<bean id="logDao" class="com.baobaotao.anno.LogDao"/>

????<bean id="userDao" class="com.baobaotao.anno.UserDao"/>

???<bean class="com.baobaotao.anno.LogonService">

???????<property name="logDao" ref="logDao"></property>

???????<property name="userDao" ref="userDao"></property>

???</bean>

</beans>


2.1.2 構(gòu)造方法注入

使用構(gòu)造函數(shù)注入的前提是Bean必須提供帶參數(shù)的構(gòu)造函數(shù)。例如

package com.baobaotao.anno;

?

import org.springframework.beans.factory.BeanNameAware;

?

public class LogonService implements BeanNameAware{

?

????public LogonService(){}

?

????public LogonService(LogDao logDao, UserDao userDao) {

????????this.logDao = logDao;

????????this.userDao = userDao;

????}

?

????private LogDao logDao;

?

????private UserDao userDao;

?

????public void setUserDao(UserDao userDao) {

????????this.userDao = userDao;

????}

?

????public void setLogDao(LogDao logDao) {

????????this.logDao = logDao;

????}

????

????public LogDao getLogDao() {

????????return logDao;

????}

????public UserDao getUserDao() {

????????return userDao;

????}

????

????public void setBeanName(String beanName) {

????????System.out.println("beanName:"+beanName); ???????

????}

????

????public void initMethod1(){

????????System.out.println("initMethod1");

????}

????public void initMethod2(){

????????System.out.println("initMethod2");

????}

}

?

bean.xml配置

<?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:context="http://www.springframework.org/schema/context"

????xsi:schemaLocation="http://www.springframework.org/schema/beans

?????????http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

?????????http://www.springframework.org/schema/context

?????????http://www.springframework.org/schema/context/spring-context-3.0.xsd"

???????default-autowire="byName">

?

????<bean id="logDao" class="com.baobaotao.anno.LogDao"/>

????<bean id="userDao" class="com.baobaotao.anno.UserDao"/>

???<bean class="com.baobaotao.anno.LogonService">

??????<constructor-arg ?ref="logDao"></constructor-arg>

???????<constructor-arg ref="userDao"></constructor-arg>

???</bean>

</beans>

?

2.1.3 工廠方法注入

非靜態(tài)工廠方法:

有些工廠方法是非靜態(tài)的,即必須實例化工廠類后才能調(diào)用工廠方法。

package com.baobaotao.ditype;

?

public class CarFactory {

???public Car createHongQiCar(){

???????Car car = new Car();

???????car.setBrand("紅旗CA72");

???????return car;

???}

???

???public static Car createCar(){

???????Car car = new Car();

???????return car;

???}

}

?

工廠類負(fù)責(zé)創(chuàng)建一個或多個目標(biāo)類實例,工廠類方法一般以接口或抽象類變量的形式返回目標(biāo)類實例,工廠類對外屏蔽了目標(biāo)類的實例化步驟,調(diào)用者甚至不用知道具體的目標(biāo)類是什么。

<?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:p="http://www.springframework.org/schema/p"

????xsi:schemaLocation="http://www.springframework.org/schema/beans

?????????http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

?

????<!-- 工廠方法-->

????<bean id="carFactory" class="com.baobaotao.ditype.CarFactory" />

????<bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar">

????</bean>

</beans>

靜態(tài)工廠方法:

很多工廠類都是靜態(tài)的,這意味著用戶在無須創(chuàng)建工廠類實例的情況下就可以調(diào)用工廠類方法,因此,靜態(tài)工廠方法比非靜態(tài)工廠方法的調(diào)用更加方便。

<?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:p="http://www.springframework.org/schema/p"

????xsi:schemaLocation="http://www.springframework.org/schema/beans

?????????http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

?

????<bean id="car6" class="com.baobaotao.ditype.CarFactory"

????????factory-method="createCar"></bean>

</beans>

?

2.2 使用注解的方式注入

2.2.1 使用@Autowired進行自動注入

Spring通過@Autowired注解實現(xiàn)Bean的依賴注入,下面是一個例子:

package com.baobaotao.anno;

?

import org.springframework.beans.factory.BeanNameAware;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Service;

//① 定義一個ServiceBean(不需要在XML中定義Bean

@Service

public class LogonService implements BeanNameAware{

????????//② 分別注入LogDaoUserDaoBean(不需要在XML中定義property屬性注入)

????@Autowired(required=false)

????private LogDao logDao;

????@Autowired

????@Qualifier("userDao")

????private UserDao userDao;

????

????public LogDao getLogDao() {

????????return logDao;

????}

????public UserDao getUserDao() {

????????return userDao;

????}

????

????public void setBeanName(String beanName) {

????????System.out.println("beanName:"+beanName); ???????

????}

????

????public void initMethod1(){

????????System.out.println("initMethod1");

????}

????public void initMethod2(){

????????System.out.println("initMethod2");

????}

}

處,我們使用@ServiceLogonService標(biāo)注為一個Bean,在處,通過@Autowired注入LogDaoUserDaoBean。@Autowired默認(rèn)按類型匹配的方式,在容器查找匹配的Bean,當(dāng)有且僅有一個匹配的Bean時,Spring將其注入到@Autowired標(biāo)注的變量中。

?

2.2.2 使用@Autowiredrequired屬性

如果容器中沒有一個和標(biāo)注變量類型匹配的Bean,Spring容器啟動時將報NoSuchBeanDefinitionException的異常。如果希望Spring即使找不到匹配的Bean完成注入也不用拋出異常,那么可以使用@Autowired(required=false)進行標(biāo)注:

@Service

public?class?LogonService implements?BeanNameAware{

????@Autowired(required=false)

????private?LogDao logDao;

????????...

}

默認(rèn)情況下,@Autowiredrequired屬性的值為true,即要求一定要找到匹配的Bean,否則將報異常。

?

2.2.3 使用@Qualifier指定注入Bean的名稱

?

如果容器中有一個以上匹配的Bean時,則可以通過@Qualifier注解限定Bean的名稱,如下所示:

@Service

public class LogonService implements BeanNameAware{

????@Autowired(required=false)

????private LogDao logDao;

????//①注入名為UserDao,類型為UserDaoBean

????@Autowired

????@Qualifier("userDao")

????private UserDao userDao;

}

?

這里假設(shè)容器有兩個類型為UserDaoBean,一個名為userDao,另一個名為otherUserDao,則處會注入名為userDaoBean

?

2.2.4 對類方法進行標(biāo)注

?

@Autowired可以對類成員變量及方法的入?yún)⑦M行標(biāo)注,下面我們在類的方法上使用@Autowired注解:

package com.baobaotao.anno;

?

import org.springframework.beans.factory.BeanNameAware;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Service;

?

@Service

public class LogonService implements BeanNameAware{

????

????private LogDao logDao;

????private UserDao userDao;

????

????

????@Autowired

????public void setLogDao(LogDao logDao) {

????????this.logDao = logDao;

????}

????

????@Autowired

????@Qualifier("userDao")

????public void setUserDao(UserDao userDao) {

????????System.out.println("auto inject");

????????this.userDao = userDao;

????}

}

如果一個方法擁有多個入?yún)?,在默認(rèn)情況下,Spring自動選擇匹配入?yún)㈩愋偷?/span>Bean進行注入。Spring允許對方法入?yún)?biāo)注@Qualifier以指定注入Bean的名稱,如下所示:

????@Autowired

????public?void?init(@Qualifier("userDao")UserDao userDao,LogDao logDao){

????????System.out.println("multi param inject");

????????this.userDao = userDao;

????????this.logDao =logDao;

????}

在以上例子中,UserDao的入?yún)⒆⑷朊麨?/span>userDaoBean,而LogDao的入?yún)⒆⑷?/span>LogDao類型的Bean

一般情況下,在Spring容器中大部分的Bean都是單實例的,所以我們一般都無須通過@Repository@Service等注解的value屬性為Bean指定名稱,也無須使用@Qualifier按名稱進行注入。

?

2.2.5 對標(biāo)準(zhǔn)注解的支持

?

此外,Spring還支持@Resource@Inject注解,這兩個標(biāo)準(zhǔn)注解和@Autowired注解的功能類似,都是對類變量及方法入?yún)⑻峁┳詣幼⑷氲墓δ堋?/span>@Resource要求提供一個Bean名稱的屬性,如果屬性為空,則自動采用標(biāo)注處的變量名或方法名作為Bean的名稱。

package com.baobaotao.anno;

?

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.annotation.Resource;

?

import org.springframework.stereotype.Component;

?

@Component

public class Boss {

????

????private Car car;

????

????public Boss(){

????????System.out.println("construct...");

????}

?

// ???@Autowired

// ???private void setCar(Car car){

// ???????System.out.println("execute in setCar");

// ???????this.car = car;

// ???}

????

????@Resource("car")

????private void setCar(Car car){

????????System.out.println("execute in setCar");

????????this.car = car;

????}

????

????@PostConstruct

????private void init1(){

????????System.out.println("execute in init1");

????}

????

????@PostConstruct

????private void init2(){

????????System.out.println("execute in init1");

????}

????

????@PreDestroy

????private void destory1(){

????????System.out.println("execute in destory1");

????}

????

????@PreDestroy

????private void destory2(){

????????System.out.println("execute in destory2");

????}

}

?

這時,如果@Resource未指定"car"屬性,則也可以根據(jù)屬性方法得到需要注入的Bean名稱??梢?/span>@Autowired默認(rèn)按類型匹配注入Bean,@Resource則按名稱匹配注入Bean。而@Inject@Autowired一樣也是按類型匹配注入的Bean的,只不過它沒有required屬性??梢姴还苁?/span>@Resource還是@Inject注解,其功能都沒有@Autowired豐富,因此除非必須,大可不必在乎這兩個注解。(類似于Xml中使用<constructor-arg ref="logDao"></constructor-arg>或者<property name="logDao" ref="logDao"></property>進行注入,如果使用了@Autowired或者Resource等,這不需要在定義Bean時使用屬性注入和構(gòu)造方法注入了)

?

2.2.6 關(guān)于Autowired@Resource

?

1.@Autowired注入是按照類型注入的,只要配置文件中的bean類型和需要的bean類型是一致的,這時候注入就沒問題。但是如果相同類型的bean不止一個,此時注入就會出現(xiàn)問題,Spring容器無法啟動。?
2.@Resourced標(biāo)簽是按照bean的名字來進行注入的,如果我們沒有在使用@Resource時指定bean的名字,同時Spring容器中又沒有該名字的bean,這時候@Resource就會退化為@Autowired即按照類型注入,這樣就有可能違背了使用@Resource的初衷。所以建議在使用@Resource時都顯示指定一下bean的名字@Resource(name="xxx")?

?

2.2.7 @Resource@Autowired生效的幾種方式

?

1.xml配置文件中顯式指定?

<!-- 為了使用Autowired標(biāo)簽,我們必須在這里配置一個bean的后置處理器 -->??

????<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"?/>???

??????

????<!-- 為了使用@Resource標(biāo)簽,這里必須配置一個后置處理器 -->??

????<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"?/>???

2.xml配置文件中使用context:annotation-config?

<context:annotation-config />


3.xml配置文件中使用context:component-scan?

<context:component-scan base-package="com.baobaotao.anno"/>

?

4.重寫Spring容器的Context,在自定義BeanFactory時調(diào)用AnnotationConfigUtils.registerAnnotationConfigProcessors()把這兩個注解處理器增加到容器中。?

編寫自己的XmlWebApplicationContext,在這個context中重寫customizeBeanFactory(),在這個方法中調(diào)用了AnnotationConfigUtils.registerAnnotationConfigProcessors()方法把這兩自動注解處理器加入到BeanDefinitions中,這樣公在web層就支持@Resource@Autowired進行自動注入。如下:

package com.alibaba.citrus.springext.support.context;

?

import com.alibaba.citrus.springext.ResourceLoadingExtendable;

import com.alibaba.citrus.springext.ResourceLoadingExtender;

import com.alibaba.citrus.springext.support.context.InheritableListableBeanFactory;

import com.alibaba.citrus.springext.support.resolver.XmlBeanDefinitionReaderProcessor;

import java.io.IOException;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

import org.springframework.context.ApplicationListener;

import org.springframework.context.annotation.AnnotationConfigUtils;

import org.springframework.core.io.Resource;

import org.springframework.core.io.support.ResourcePatternResolver;

?

public class XmlWebApplicationContext extends org.springframework.web.context.support.XmlWebApplicationContext implements ResourceLoadingExtendable {

????private ResourceLoadingExtender resourceLoadingExtender;

????private boolean parentResolvableDependenciesAccessible = true;

?

????public XmlWebApplicationContext() {

????}

?

????public boolean isParentResolvableDependenciesAccessible() {

????????return this.parentResolvableDependenciesAccessible;

????}

?

????public void setParentResolvableDependenciesAccessible(boolean parentResolvableDependenciesAccessible) {

????????this.parentResolvableDependenciesAccessible = parentResolvableDependenciesAccessible;

????}

?

????public void setResourceLoadingExtender(ResourceLoadingExtender resourceLoadingExtender) {

????????if(this.resourceLoadingExtender != null) {

????????????this.getApplicationListeners().remove(this.resourceLoadingExtender);

????????}

?

????????this.resourceLoadingExtender = resourceLoadingExtender;

????????if(resourceLoadingExtender instanceof ApplicationListener) {

????????????this.addApplicationListener((ApplicationListener)resourceLoadingExtender);

????????}

?

????}

?

????protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {

????????(new XmlBeanDefinitionReaderProcessor(beanDefinitionReader)).addConfigurationPointsSupport();

????}

?

????protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {

????????super.customizeBeanFactory(beanFactory);

    //AnnotationConfigUtils.registerAnnotationConfigProcessors()方法把這兩自動注解處理器加入到BeanDefinitions,web層就支持@Resource@Autowired進行自動注入

????????AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory, (Object)null);

????}

?

????protected DefaultListableBeanFactory createBeanFactory() {

????????return (DefaultListableBeanFactory)(this.isParentResolvableDependenciesAccessible()?new InheritableListableBeanFactory(this.getInternalParentBeanFactory()):super.createBeanFactory());

????}

?

????protected Resource getResourceByPath(String path) {

????????Resource resource = null;

????????if(this.resourceLoadingExtender != null) {

????????????resource = this.resourceLoadingExtender.getResourceByPath(path);

????????}

?

????????if(resource == null) {

????????????resource = super.getResourceByPath(path);

????????}

?

????????return resource;

????}

?

????protected ResourcePatternResolver getResourcePatternResolver() {

????????final ResourcePatternResolver defaultResolver = super.getResourcePatternResolver();

????????return new ResourcePatternResolver() {

????????????public Resource[] getResources(String locationPattern) throws IOException {

????????????????ResourcePatternResolver resolver = null;

????????????????if(XmlWebApplicationContext.this.resourceLoadingExtender != null) {

????????????????????resolver = XmlWebApplicationContext.this.resourceLoadingExtender.getResourcePatternResolver();

????????????????}

?

????????????????if(resolver == null) {

????????????????????resolver = defaultResolver;

????????????????}

?

????????????????return resolver.getResources(locationPattern);

????????????}

?

????????????public ClassLoader getClassLoader() {

????????????????return defaultResolver.getClassLoader();

????????????}

?

????????????public Resource getResource(String location) {

????????????????return defaultResolver.getResource(location);

????????????}

????????};

????}

}

三、?×××

1、克隆

git clone?https://github.com/spring-projects/spring-framework.git

2、使用maven

1Core

支持dependency injection, events, resources, i18n, validation, data binding, type conversion, SpEL, AOP,其依賴為:

<dependency>

????<groupId>org.springframework</groupId>

????<artifactId>spring-core</artifactId>

????<version>5.1.2.RELEASE</version>

</dependency>

2WebMVC

支持MVC, View Technologies, CORS, Web Socket, RESTful,同時繼承Spring Web的功能core HTTP integration,包括Servlet filters, Spring HTTP Invoker, infrastructure to integrate with?
other web frameworks and HTTP technologies e.g. Hessian, Burlap。其依賴為:

<dependency>

????<groupId>org.springframework</groupId>

????<artifactId>spring-webmvc</artifactId>

????<version>5.1.2.RELEASE</version>

</dependency>

注意:依賴了spring-webmvc就不需要依賴spring-web

3spring-boot-starter-web

注意:啟動器spring-boot-starter-web基于Spring MVC構(gòu)建RESTful風(fēng)格的web應(yīng)用,使用內(nèi)嵌tomcat作為默認(rèn)容器

?

3、使用Gradle

1spring-corespring-webmvc

dependencies?{

api 'org.springframework:spring-core:5.0.8.RELEASE'

api 'org.springframework:spring-webmvc:5.0.8.RELEASE'

}

或者

dependencies?{

compile group: 'org.springframework', name: 'spring-core', version: '5.0.8.RELEASE'

compile group: 'org.springframework', name: 'spring-webmvc', version: '5.0.8.RELEASE'

}

2spring-boot-starter-web

dependencies?{

????compile("org.springframework.boot:spring-boot-starter-web")

}

?

注意:啟動器spring-boot-starter-web基于Spring MVC構(gòu)建RESTful風(fēng)格的web應(yīng)用,使用內(nèi)嵌tomcat作為默認(rèn)容器

?

可以在Spring Boot”中了解注解和啟動器清單。


四、SOAP Web Service生產(chǎn)服務(wù)

1)依賴Spring Web

?

***Maven***

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web-services</artifactId>

</dependency>

?

***Gradle***

dependencies?{

????compile("org.springframework.boot:spring-boot-starter-web-services")

}

?

2)定義web service domain

使用XSDXML schema file)定義Domain。

?

例如:在resources目錄下創(chuàng)建countries.xsd文件來定義國家的名稱、人口、首都和貨幣。

<xs:schema?xmlns:xs="http://www.w3.org/2001/XMLSchema"?xmlns:tns="http://jiaxiaomei.com/test/soap-test"

targetNamespace="http://jiaxiaomei.com/test/soap-test"?elementFormDefault="qualified">

?

????<xs:element?name="getCountryRequest">

????????<xs:complexType>

????????????<xs:sequence>

????????????????<xs:element?name="name"?type="xs:string"/>

????????????</xs:sequence>

????????</xs:complexType>

????</xs:element>

?

????<xs:element?name="getCountryResponse">

????????<xs:complexType>

????????????<xs:sequence>

????????????????<xs:element?name="country"?type="tns:country"/>

????????????</xs:sequence>

????????</xs:complexType>

????</xs:element>

?

????<xs:complexType?name="country">

????????<xs:sequence>

????????????<xs:element?name="name"?type="xs:string"/>

????????????<xs:element?name="population"?type="xs:int"/>

????????????<xs:element?name="capital"?type="xs:string"/>

????????????<xs:element?name="currency"?type="tns:currency"/>

????????</xs:sequence>

????</xs:complexType>

?

????<xs:simpleType?name="currency">

????????<xs:restriction?base="xs:string">

????????????<xs:enumeration?value="GBP"/>

????????????<xs:enumeration?value="EUR"/>

????????????<xs:enumeration?value="PLN"/>

????????</xs:restriction>

????</xs:simpleType>

</xs:schema>

?

3)產(chǎn)生Domain

maven或者gradle基于xsd文件自動創(chuàng)建Domain類。

?

***Maven*** 修改pom.xml

首先新增依賴:

<dependency>

<groupId>wsdl4j</groupId>

<artifactId>wsdl4j</artifactId>

</dependency>

然后增加構(gòu)建插件:

<!-- tag::JAXB2, xsd[] -->

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>jaxb2-maven-plugin</artifactId>

<version>1.6</version>

<executions>

<execution>

<id>xjc</id>

<goals>

<goal>xjc</goal>

</goals>

</execution>

</executions>

<configuration>

<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>

<outputDirectory>${project.basedir}/src/main/java</outputDirectory>

<clearOutputDir>false</clearOutputDir>

</configuration>

</plugin>

<!-- end::JAXB2, xsd[] -->

?

?

注意plugin標(biāo)簽放在plugins標(biāo)簽里面。

保存后,eclipse會自動執(zhí)行xjc,在java目錄下自動生成六個java文件:


親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


***Gradle*** 需要在build.gradle中配置JAXB

A、在bootJar里面增加:

from genJaxb.classesDir

B、新增configurations

configurations {

????jaxb

}

C、在dependencies里面增加對Spring WSJAXB的依賴:

????compile("wsdl4j:wsdl4j:1.6.1")

????jaxb("org.glassfish.jaxb:jaxb-xjc:2.2.11")

????compile(files(genJaxb.classesDir).builtBy(genJaxb))

D、增加genJaxb任務(wù)(Ant任務(wù),因為gradle還不支持JAXB任務(wù)):

task?genJaxb {

????ext.sourcesDir = "${buildDir}/generated-sources/jaxb"

????ext.classesDir = "${buildDir}/classes/jaxb"

????ext.schema = "src/main/resources/countries.xsd"

?

????outputs.dir classesDir

?

????doLast() {

????????project.ant {

????????????taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",

????????????????????classpath: configurations.jaxb.asPath

????????????mkdir(dir: sourcesDir)

????????????mkdir(dir: classesDir)

?

????????????xjc(destdir: sourcesDir, schema: schema) {

????????????????arg(value: "-wsdl")

????????????????produces(dir: sourcesDir, includes: "**/*.java")

????????????}

?

????????????javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true,

????????????????????debugLevel: "lines,vars,source",

????????????????????classpath: configurations.jaxb.asPath) {

????????????????src(path: sourcesDir)

????????????????include(name: "**/*.java")

????????????????include(name: "*.java")

????????????}

?

????????????copy(todir: classesDir) {

????????????????fileset(dir: sourcesDir, erroronmissingdir: false) {

????????????????????exclude(name: "**/*.java")

????????????????}

????????????}

????????}

????}

}

?

E、增加afterEclipseImport任務(wù)

task?afterEclipseImport {

dependsOn "genJaxb"

}

?

保存后自動生成java類,注意gradle采用了ant任務(wù),比maven復(fù)雜很多。

關(guān)于jaxbant任務(wù)的更多知識,參見“9JAXBANT”。

?

4)創(chuàng)建Repository

該類需要注解@Component,給web service提供數(shù)據(jù)。

?

例如:

A、創(chuàng)建CountryRepository類,并增加注解@Component

?

B、增加一個靜態(tài)成員:

private static final Map<String, Country> countries = new HashMap<>();

?

C、增加初始化數(shù)據(jù)的方法initData,返回類型為void,代碼為:

Country spain = new Country();

spain.setName("Spain");

spain.setCapital("Madrid");

spain.setCurrency(Currency.EUR);

spain.setPopulation(46704314);

?

countries.put(spain.getName(), spain);

?

Country poland = new Country();

poland.setName("Poland");

poland.setCapital("Warsaw");

poland.setCurrency(Currency.PLN);

poland.setPopulation(38186860);

?

countries.put(poland.getName(), poland);

?

Country uk = new Country();

uk.setName("United Kingdom");

uk.setCapital("London");

uk.setCurrency(Currency.GBP);

uk.setPopulation(63705000);

?

countries.put(uk.getName(), uk);

?

D、增加查找方法findCountry,參數(shù)為name,返回Country

Assert.notNull(name, "The country's name must not be null");

return countries.get(name);

?

5)創(chuàng)建service endpoint來處理SOAP請求

?

A、創(chuàng)建endpoint類,加注解@Endpoint,增加構(gòu)造函數(shù)并注解@Autowired

?

按照country例子:

@Autowired

public CountryEndpoint(CountryRepository countryRepository) {

this.countryRepository = countryRepository;

}

?

其中,@Endpoint注冊一個Spring WS類作為處理SOAP消息的候選者。

?

B、增加靜態(tài)成員NAMESPACE_URI

例如:

private static final String NAMESPACE_URI = "http://jiaxiaomei.com/test/soap-test";

?

C、增加Repository的私有成員

例如:

private CountryRepository countryRepository;

?

D、增加查詢方法,注解@PayloadRoot、@RequestPayload@ResponsePayload

例如:

@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")

@ResponsePayload

public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {

GetCountryResponse response = new GetCountryResponse();

response.setCountry(countryRepository.findCountry(request.getName()));

?

return response;

}

?

其中,@PayloadRootSpring WS提供,選擇處理方法,屬性包括namespacelocalpart。

@RequestPayloadSpring WS提供,表示SOAP消息將會綁定到request參數(shù)。

@ResponsePayloadSpring WS提供,映射返回值到響應(yīng)負(fù)載中。

?

6)配置web service bean

A、從WsConfigurerAdapter繼承一個webservice配置類,并注解@EnableWs@Configuration

例如:

@EnableWs

@Configuration

public?class?WebServiceConfig extends?WsConfigurerAdapter {

?

B、自定義DispatcherServlet bean

Spring WS使用不同的servlet類型來處理SOAP消息,該類型是MessageDispatcherServlet。

需要注入ApplicationContext到方法中,這樣才能讓Spring WS自動偵測到Spring bean。

重新命名MessageDispatcherServlet注入方法,就不替換Spring Boot的默認(rèn)DispatcherServlet bean,默認(rèn)bean通過鏈接點/提供服務(wù),自定義的MessageDispatcherServlet通過ServletRegistrationBean重新設(shè)定鏈接點。

前面的@Endpoint注解已經(jīng)提示DefaultMethodEndpointAdapter設(shè)置注解驅(qū)動Spring WS編程模型。這里就采用這種注解驅(qū)動模型。

?

例如:

@Bean

public?ServletRegistrationBean?messageDispatcherServlet(ApplicationContext applicationContext) {

MessageDispatcherServlet?servlet?= new?MessageDispatcherServlet();

servlet.setApplicationContext(applicationContext);

servlet.setTransformWsdlLocations(true);

return?new?ServletRegistrationBean(servlet, "/ws/*");

}

?

C、基于DefaultWsdl11Definition構(gòu)建WSDL定義

DefaultWsdl11Definition使用XsdSchema接口展示WSDL1.1標(biāo)準(zhǔn)。

例如:

@Bean(name = "countries")

public?DefaultWsdl11Definition?defaultWsdl11Definition(XsdSchema countriesSchema) {

DefaultWsdl11Definition?wsdl11Definition?= new?DefaultWsdl11Definition();

wsdl11Definition.setPortTypeName("CountriesPort");

wsdl11Definition.setLocationUri("/ws");

wsdl11Definition.setTargetNamespace("http://jiaxiaomei.com/test/soap-test");

wsdl11Definition.setSchema(countriesSchema);

return?wsdl11Definition;

}

其中@Bean的屬性name實際上指定了wsdl的文件名,所以,wsdl文件可以獲得于這個鏈接:

http://<host>:<port>/ws/countries.wsdl

?

7)構(gòu)建Application類,注解@SpringBootApplication

Build后啟動這個服務(wù),創(chuàng)建一個請求xml,編寫進入SOAP請求。

例如:

<soapenv:Envelope?xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"

??xmlns:gs="http://jiaxiaomei.com/test/soap-test">

???<soapenv:Header/>

???<soapenv:Body>

??????<gs:getCountryRequest>

?????????<gs:name>Spain</gs:name>

??????</gs:getCountryRequest>

???</soapenv:Body>

</soapenv:Envelope>

?

下載curl,地址:https://curl.haxx.se/,設(shè)置bin目錄到環(huán)境變量path。然后,在命令行中使用curl發(fā)送soap請求,如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


下載libxml2,包含三個文件iconv-1.14-win32-x86_64.7zzlib-1.2.8-win32-x86_64.7zlibxml2-2.9.3-win32-x86_64.7z,下載地址:https://www.zlatkovic.com/pub/libxml/64bit/;解壓后把三個bin都放到path環(huán)境變量中。然后在命令行中執(zhí)行:

curl --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws |xmllint --format

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework

這讓soap response文件更規(guī)整。


五、 RESTful Web Service生產(chǎn)服務(wù)

參考:https://spring.io/guides/gs/rest-service/做了一個實際例子。

1)新建一個gradle project,修改build.gradle

A、修改依賴為:

dependencies?{

????// This dependency is exported to consumers, that is to say found on their compile classpath.

????//api 'org.springframework.boot:spring-boot-starter-web:2.1.0.RELEASE'

?

????// This dependency is used internally, and not exposed to consumers on their own compile classpath.

????implementation 'org.springframework.boot:spring-boot-starter-web:2.1.0.RELEASE'

?

????// spring-boot-starter-test based on JUnit test framework

????testImplementation 'org.springframework.boot:spring-boot-starter-test:2.1.0.RELEASE'

}

?

B、修改構(gòu)建腳本

buildscript?{

????repositories?{

????????mavenCentral()

????}

????dependencies?{

????????classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.0.RELEASE")

????}

}

?

C、引用插件

apply?plugin: 'eclipse'

apply?plugin: 'idea'

apply?plugin: 'org.springframework.boot'

apply?plugin: 'io.spring.dependency-management'

?

D、增加jar包輸出信息

bootJar {

????baseName = 'restfultest'

????version = ?'0.1.0'

}

?

E、增加兼容性信息

sourceCompatibility?= 1.8

targetCompatibility?= 1.8

?

保存后刷新項目(項目右鍵菜單àgradleàrefresh gradle project),提示:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


修改項目gradle設(shè)置:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


2)新建一個model


親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


3)新建一個controller

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


@RestControllerSpring4里面引入,參見“5、Spring Boot”的“Annotation”,用于標(biāo)注類為控制器,該控制器每個方法都返回一個model,而不是view

@RequestMapping注解映射HTTP請求http://host:port/msg到所標(biāo)注的方法上。

@RequestParam注解綁定HTTP請求參數(shù)到所標(biāo)注的方法參數(shù)上(http://host:port/msg?name=)。

注意:這是一個RESTful web service controller,而不是傳統(tǒng)的MVC controller。這個controller僅僅返回一個model對象,這個對象數(shù)據(jù)直接使用JSON寫到HTTP responseMappingJackson2HttpMessageConverter自動被執(zhí)行來支持Jackson 2。傳統(tǒng)MVC controller使用view技術(shù)在server-side把數(shù)據(jù)轉(zhuǎn)換為html

4)新建一個Application

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


5)執(zhí)行

使用Boot Dashboard的左上角按鈕啟動服務(wù)。

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


Chrome中驗證:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


六、 SOAP Web Service消費服務(wù)

參考:https://spring.io/guides/gs/consuming-web-service/

?

1)新建一個maven項目

修改pom.xml

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


2)編寫任務(wù),自動從WSDL產(chǎn)生類。

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


3)創(chuàng)建一個web service客戶端

WebServiceGatewaySupport類繼承而來:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


其中getCountry方法完成SOAP數(shù)據(jù)交換任務(wù)。

GetCountryRequestGetCountryResponse都是jaxb自動產(chǎn)生的。

WebServiceGatewaySupport的方法getWebServiceTemplate獲得WebServiceTemplate,然后使用marshalSendAndReceive方法來實際完成wsdl文件接收和解析。

SoapActionCallback用來獲取SOAPAction headerWSDL解析時需要這個頭,其中包含<soap:operation/>?元素。

4)配置web service

Spring WS通過Spring FrameworkOXM模塊中的Jaxb2Marshaller來存取XML請求。

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


marshaller bean指向domain對象集合,在XMLPOJOs之間轉(zhuǎn)換。

countryClient bean用來配置web serviceURI,并綁定marshaller。


5)配置應(yīng)用入口類

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


七、 RESTful Web Service消費服務(wù)

參考:https://spring.io/guides/gs/consuming-rest/

?

1)新建一個gradle project,修改build.gradle,如下

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


2)創(chuàng)建一個domain類,如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


3)創(chuàng)建一個Application類,如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


其中服務(wù)地址引用RESTful Web Service生產(chǎn)服務(wù)”,執(zhí)行后輸出:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


4)改造Application

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


其中@BeanrestTemplate注解到CommandLineRunner回調(diào)函數(shù)中。

?

由于和RESTful Web Service生產(chǎn)服務(wù)”使用的8080端口沖突,所以需要增加Application.yml,如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


啟動后,如下:

親自動手搭建微服務(wù)框架和測試環(huán)境-11-Spring Framework


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI