領先一步
VMware 提供培訓和認證,以加速您的進程。
了解更多在這篇部落格中,我想看看並展示 Spring Boot 1.2 中的許多新功能,這些功能讓來自或以其他方式建構在 Java EE 上的開發人員的生活更加輕鬆。
值得一提的是,當然,Spring 之前已經可以實現許多這樣的支援,但現在有了 Spring Boot 1.2,一切都變得非常容易!
首先,這是一個範例程式,後面附有說明。
package demo;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jms.JMSException;
import javax.persistence.*;
import javax.transaction.Transactional;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.io.Serializable;
import java.util.Collection;
import java.util.logging.Logger;
@SpringBootApplication
public class Application {
@Named
public static class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
this.register(GreetingEndpoint.class);
this.register(JacksonFeature.class);
}
}
@Named
@Transactional
public static class GreetingService {
@Inject
private JmsTemplate jmsTemplate;
@PersistenceContext
private EntityManager entityManager;
public void createGreeting(String name, boolean fail) {
Greeting greeting = new Greeting(name);
this.entityManager.persist(greeting);
this.jmsTemplate.convertAndSend("greetings", greeting);
if (fail) {
throw new RuntimeException("simulated error");
}
}
public void createGreeting(String name) {
this.createGreeting(name, false);
}
public Collection<Greeting> findAll() {
return this.entityManager
.createQuery("select g from " + Greeting.class.getName() + " g", Greeting.class)
.getResultList();
}
public Greeting find(Long id) {
return this.entityManager.find(Greeting.class, id);
}
}
@Named
@Path("/hello")
@Produces({MediaType.APPLICATION_JSON})
public static class GreetingEndpoint {
@Inject
private GreetingService greetingService;
@POST
public void post(@QueryParam("name") String name) {
this.greetingService.createGreeting(name);
}
@GET
@Path("/{id}")
public Greeting get(@PathParam("id") Long id) {
return this.greetingService.find(id);
}
}
@Entity
public static class Greeting implements Serializable {
@Id
@GeneratedValue
private Long id;
@Override
public String toString() {
return "Greeting{" +
"id=" + id +
", message='" + message + '\'' +
'}';
}
private String message;
public String getMessage() {
return message;
}
public Greeting(String name) {
this.message = "Hi, " + name + "!";
}
Greeting() {
}
}
@Named
public static class GreetingServiceClient {
@Inject
private GreetingService greetingService;
@PostConstruct
public void afterPropertiesSet() throws Exception {
greetingService.createGreeting("Phil");
greetingService.createGreeting("Dave");
try {
greetingService.createGreeting("Josh", true);
} catch (RuntimeException re) {
Logger.getLogger(Application.class.getName()).info("caught exception...");
}
greetingService.findAll().forEach(System.out::println);
}
}
@Named
public static class GreetingMessageProcessor {
@JmsListener(destination = "greetings")
public void processGreeting(Greeting greeting) throws JMSException {
System.out.println("received message: " + greeting);
}
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
完整的程式碼清單,包括非常稀疏的 application.properties
和 Maven 建置檔,都可以在網路上找到。
此範例 展示了 Boot 的全新 JAX-RS 自動配置 (在本例中,使用 Jersey 2.x) 在 GreetingEndpoint
中。 請注意讓所有這些都運作起來是多麼方便! 唯一需要注意的是,您需要指定一個 ResourceConfig
子類別,讓 Jersey 知道要註冊哪些組件。
它展示了使用 新的自動配置 JTA 支援的全域交易。 JTA 是 X/Open XA 協定的 Java API,它允許多個相容的交易資源 (例如訊息佇列和資料庫) 參與單一交易。 為此,我們使用了 Atomikos 獨立 JTA 提供者。 我們也可以輕鬆地使用 Bitronix;如果您引入適當的啟動器,兩者都會自動配置。 在這個範例中,在 GreetingService
中,JMS 和 JPA 工作是作為全域交易的一部分完成的。 我們透過建立 3 個交易並模擬第三個交易的回滾來展示這一點。 您應該在主控台中看到從 JDBC javax.sql.DataSource
資料來源傳回了兩個記錄,以及從嵌入式 JMS javax.jms.Destination
目的地收到了兩個記錄。
此範例還使用了 Wildfly (來自 RedHat) 應用程式伺服器的令人驚嘆的 Undertow 嵌入式 HTTP 伺服器,而不是 (預設的) Apache Tomcat。 使用 Undertow 與使用 Jetty 或 Tomcat 一樣容易 - 只需排除 org.springframework.boot:spring-boot-starter-tomcat
並新增 org.springframework.boot:spring-boot-starter-undertow
! 這個貢獻最初是第三方 PR - 感謝 Ivan Sopov! 真是太棒了。
為了保持一致性,該範例也使用了 JSR 330。 JSR 330 描述了一組註釋,您可以在 WebLogic 等專有應用程式伺服器以及 Google Guice 或 Spring 等依賴注入容器中以可移植的方式使用這些註釋。 我還使用 JSR 250 註釋 (定義為 Java EE 5 的一部分) 來示範生命週期掛鉤。
此範例依賴於 Spring Boot 自動配置和嵌入式、記憶體中的 H2 javax.sql.DataSource
和 - Spring Boot 自動配置和嵌入式、記憶體中的 HornetQ javax.jms.ConnectionFactory
。 如果您想連接到傳統的非嵌入式實例,可以透過在 application.yml
或 application.properties
中指定屬性 (例如 spring.hornetq.host
),或者簡單地定義適當類型的 @Bean
來實現。
此範例也使用了新的 @SpringBootApplication
註釋,它結合了 @Configuration
、@EnableAutoConfiguration
和 @ComponentScan
。 真棒!
儘管此範例使用了許多相當熟悉的 Java EE API,但這仍然只是典型的 Spring Boot,因此預設情況下,您可以使用 java -jar ee.jar
執行此應用程式,或輕鬆地將其部署到以流程為中心的 平台即服務 產品 (例如 Heroku 或 Cloud Foundry)。 如果您想將其部署到獨立應用程式伺服器 (例如 Apache Tomcat 或 Websphere,或兩者之間的任何伺服器),可以很簡單地將建置轉換為 .war
並將其相應地部署到任何 Servlet 3 容器。
如果您將應用程式部署到更經典的應用程式伺服器,Spring Boot 也可以利用 AS 的設施。 例如,可以非常簡單地使用 JNDI 綁定的 JMS ConnectionFactory
、JDBC DataSource
或 JTA UserTransaction
。
我個人會質疑很多這些 API。 您真的需要分散式、多資源交易嗎? 在今天的 分散式世界中,請考慮全域交易管理員是一種架構氣味。 當 Spring 提供更豐富、整合的基於 Spring MVC 的堆疊 (包括 MVC、REST、HATEOAS、OAuth 和 Websocket 支援) 時,您真的需要使用 JAX-RS 嗎? JPA 是一個與基於 SQL 的 javax.sql.DataSource
通訊的好 API,但 Spring Data 儲存庫 (當然包括對 JPA 的支援,也包括對 Cassandra、MongoDB、Redis、CouchBase 和越來越多的替代技術的支援) 將許多樣板程式碼減少為通用案例的簡單介面定義。 所以,您真的需要所有這些嗎? 很可能您需要,而且 - 與往常一樣 - 選擇權在您。 這就是這個版本如此酷的原因! 更多的力量,更多的選擇。
實際上很多。有一大堆新功能。我根本無法在這裡全部涵蓋。所以我不會嘗試。查看發布說明以獲取完整資訊!