您好,登錄后才能下訂單哦!
Spring 5的架構(gòu)圖如下:
各組件之間的依賴圖如下:
Spring5有20 個組件(1300多個文件),這些組件被分別整合在核心容器(Core Container)、AOP(Aspect Oriented Programming)和設(shè)備支持(Instrmentation)、數(shù)據(jù)訪問及集成(Data Access/Integeration)、Web、報文發(fā)送(Messaging)、Test中。
1、核心容器
由 spring-beans、spring-core、spring-context 和 spring-expression(Spring 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 模塊主要提供一個抽象層以支撐?OXM(OXM 是?Object-to-XML-Mapping 的縮寫,它是一個?O/M-mapper,將?java 對象映射成?XML 數(shù)據(jù),或者將?XML 數(shù)據(jù)映射成?java 對象),例如:JAXB,Castor, XMLBeans, JiBX 和?XStream 等。
?
4、Web
由 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è)都是非常重要的。
Bean配置信息定義了Bean的實現(xiàn)及依賴關(guān)系,Spring容器根據(jù)各種形式的Bean配置信息在容器內(nèi)部建立Bean定義注冊表,然后根據(jù)注冊表加載、實例化Bean,并建立Bean和Bean的依賴關(guān)系,最后將這些準(zhǔn)備就緒的Bean放到Bean緩存池中,以供外層的應(yīng)用程序進行調(diào)用。下圖是一張老圖:
1、bean配置
bean配置有三種方法:
基于xml配置Bean
使用注解定義Bean
基于java類提供Bean定義信息
?
1.1 基于xml配置Bean
?對于基于XML的配置,Spring 2.0以后使用Schema的格式,使得不同類型的配置擁有了自己的命名空間,是配置文件更具擴展性。
①默認(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的配置片段如下所示:
一般情況下,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)。
下面是使用注解定義一個DAO的Bean:
package com.baobaotao.anno;
?
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
//①通過Repository定義一個DAO的Bean
?
@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、Service及Web層的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-scan的base-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();
????}
????//③定義了logonService的Bean
????@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和一個LogDao的Bean,它們的Bean名稱分別是userDao和logDao。在③處,又定義了一個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;
//① 定義一個Service的Bean(不需要在XML中定義Bean)
@Service
public class LogonService implements BeanNameAware{
????????//② 分別注入LogDao及UserDao的Bean(不需要在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");
????}
}
在①處,我們使用@Service將LogonService標(biāo)注為一個Bean,在②處,通過@Autowired注入LogDao及UserDao的Bean。@Autowired默認(rèn)按類型匹配的方式,在容器查找匹配的Bean,當(dāng)有且僅有一個匹配的Bean時,Spring將其注入到@Autowired標(biāo)注的變量中。
?
2.2.2 使用@Autowired的required屬性
如果容器中沒有一個和標(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)情況下,@Autowired的required屬性的值為true,即要求一定要找到匹配的Bean,否則將報異常。
?
2.2.3 使用@Qualifier指定注入Bean的名稱
?
如果容器中有一個以上匹配的Bean時,則可以通過@Qualifier注解限定Bean的名稱,如下所示:
@Service
public class LogonService implements BeanNameAware{
????@Autowired(required=false)
????private LogDao logDao;
????//①注入名為UserDao,類型為UserDao的Bean
????@Autowired
????@Qualifier("userDao")
????private UserDao userDao;
}
?
這里假設(shè)容器有兩個類型為UserDao的Bean,一個名為userDao,另一個名為otherUserDao,則①處會注入名為userDao的Bean。
?
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>userDao的Bean,而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
(1)Core
支持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>
(2)WebMVC
支持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
(3)spring-boot-starter-web
注意:啟動器spring-boot-starter-web基于Spring MVC構(gòu)建RESTful風(fēng)格的web應(yīng)用,使用內(nèi)嵌tomcat作為默認(rèn)容器
?
3、使用Gradle
(1)spring-core和spring-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'
}
(2)spring-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”中了解注解和啟動器清單。
(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
使用XSD(XML 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文件:
***Gradle*** 需要在build.gradle中配置JAXB:
A、在bootJar里面增加:
from genJaxb.classesDir
B、新增configurations:
configurations {
????jaxb
}
C、在dependencies里面增加對Spring WS和JAXB的依賴:
????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)于jaxb和ant任務(wù)的更多知識,參見“9、JAXB和ANT”。
?
(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;
}
?
其中,@PayloadRoot由Spring WS提供,選擇處理方法,屬性包括namespace和localpart。
@RequestPayload由Spring WS提供,表示SOAP消息將會綁定到request參數(shù)。
@ResponsePayload由Spring 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請求,如下:
下載libxml2,包含三個文件iconv-1.14-win32-x86_64.7z、zlib-1.2.8-win32-x86_64.7z和libxml2-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
這讓soap response文件更規(guī)整。
參考: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),提示:
修改項目gradle設(shè)置:
(2)新建一個model
(3)新建一個controller
@RestController在Spring4里面引入,參見“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 response,MappingJackson2HttpMessageConverter自動被執(zhí)行來支持Jackson 2。傳統(tǒng)MVC controller使用view技術(shù)在server-side把數(shù)據(jù)轉(zhuǎn)換為html。
(4)新建一個Application
(5)執(zhí)行
使用Boot Dashboard的左上角按鈕啟動服務(wù)。
在Chrome中驗證:
參考:https://spring.io/guides/gs/consuming-web-service/
?
(1)新建一個maven項目
修改pom.xml
(2)編寫任務(wù),自動從WSDL產(chǎn)生類。
(3)創(chuàng)建一個web service客戶端
從WebServiceGatewaySupport類繼承而來:
其中getCountry方法完成SOAP數(shù)據(jù)交換任務(wù)。
GetCountryRequest和GetCountryResponse都是jaxb自動產(chǎn)生的。
WebServiceGatewaySupport的方法getWebServiceTemplate獲得WebServiceTemplate,然后使用marshalSendAndReceive方法來實際完成wsdl文件接收和解析。
SoapActionCallback用來獲取SOAPAction header,WSDL解析時需要這個頭,其中包含<soap:operation/>?元素。
(4)配置web service
Spring WS通過Spring Framework的OXM模塊中的Jaxb2Marshaller來存取XML請求。
marshaller bean指向domain對象集合,在XML和POJOs之間轉(zhuǎn)換。
countryClient bean用來配置web service的URI,并綁定marshaller。
(5)配置應(yīng)用入口類
參考:https://spring.io/guides/gs/consuming-rest/
?
(1)新建一個gradle project,修改build.gradle,如下
(2)創(chuàng)建一個domain類,如下:
(3)創(chuàng)建一個Application類,如下:
其中服務(wù)地址引用“RESTful Web Service生產(chǎn)服務(wù)”,執(zhí)行后輸出:
(4)改造Application類
其中@Bean把restTemplate注解到CommandLineRunner回調(diào)函數(shù)中。
?
由于和“RESTful Web Service生產(chǎn)服務(wù)”使用的8080端口沖突,所以需要增加Application.yml,如下:
啟動后,如下:
免責(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)容。