osgi架构与linux_OSGi:进入微服务架构的门户
osgi架構與linux
在構建可擴展,可靠的分布式系統的背景下,“模塊化”和“微服務體系結構”這兩個術語如今經常出現。 眾所周知,Java平臺本身在模塊化方面很弱( Java 9將通過交付Jigsaw項目來解決此問題),這為OSGi和JBoss Modules等框架的出現提供了機會。
當我在2007年第一次聽說OSGi時 ,我真的很高興Java應用程序可以在其之上構建而受益。 但是很快就產生了挫敗感,而不是興奮感:沒有工具支持,兼容的庫和框架非常有限,非常不穩定,難以對運行時進行故障排除。 顯然,普通的Java開發人員還沒有準備好使用它,因此,我不得不把它放在架子上。 多年來, OSGi已經成熟很多,并得到了廣泛的社區支持。
好奇的讀者可能會問:特別是使用模塊和OSGi有什么好處? 僅舉幾個問題,它有助于解決:
- 顯式(和版本控制)依賴關系管理:模塊聲明所需的內容(以及可選的版本范圍)
- 占用空間小:模塊未包裝所有依賴項
- 易于發布:模塊可以獨立開發和發布
- 熱部署:可以在不影響其他模塊的情況下重新部署各個模塊
在今天的帖子中,我們將對使用OSGi構建模塊化Java應用程序的最新技術水平進行10000英尺的考察。 撇開OSGi的好壞進行討論,我們將構建一個包含以下模塊的示例應用程序:
- 數據訪問模塊
- 商業服務模塊
- REST服務模塊
用于數據訪問的Apache OpenJPA 2.3.0 / JPA 2.0 (不幸的是,我們選擇的OSGi實現尚未支持JPA 2.1 ),用于REST層的Apache CXF 3.0.1 / JAX-RS 2.0是應用程序的兩個主要構建塊。 我發現Christian Schneider的博客Liquid Reality是有關OSGi (以及許多其他主題)的寶貴信息來源。
在OSGi世界中,這些模塊稱為bundles 。 捆綁包顯示了它們的依賴關系(導入包)和它們公開的包(導出包),因此其他捆綁包可以使用它們。 Apache Maven也支持此打包模型。 捆綁包由OSGi運行時或容器管理,在我們的情況下將是Apache Karaf 3.0.1 (實際上,這是我們需要下載 和解壓縮的內容)。
讓我停止說話,更好地顯示一些代碼。 我們將從頂部( REST )開始,一直到底部(數據訪問),因為它更容易遵循。 我們的PeopleRestService是JAX-RS 2.0服務實現的典型示例:
package com.example.jaxrs;import java.util.Collection;import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo;import com.example.data.model.Person; import com.example.services.PeopleService;@Path( "/people" ) public class PeopleRestService {private PeopleService peopleService;@Produces( { MediaType.APPLICATION_JSON } )@GETpublic Collection< Person > getPeople( @QueryParam( "page") @DefaultValue( "1" ) final int page ) {return peopleService.getPeople( page, 5 );}@Produces( { MediaType.APPLICATION_JSON } )@Path( "/{email}" )@GETpublic Person getPerson( @PathParam( "email" ) final String email ) {return peopleService.getByEmail( email );}@Produces( { MediaType.APPLICATION_JSON } )@POSTpublic Response addPerson( @Context final UriInfo uriInfo,@FormParam( "email" ) final String email, @FormParam( "firstName" ) final String firstName, @FormParam( "lastName" ) final String lastName ) {peopleService.addPerson( email, firstName, lastName );return Response.created( uriInfo.getRequestUriBuilder().path( email ).build() ).build();}@Produces( { MediaType.APPLICATION_JSON } )@Path( "/{email}" )@PUTpublic Person updatePerson( @PathParam( "email" ) final String email, @FormParam( "firstName" ) final String firstName, @FormParam( "lastName" ) final String lastName ) {final Person person = peopleService.getByEmail( email );if( firstName != null ) {person.setFirstName( firstName );}if( lastName != null ) {person.setLastName( lastName );}return person; }@Path( "/{email}" )@DELETEpublic Response deletePerson( @PathParam( "email" ) final String email ) {peopleService.removePerson( email );return Response.ok().build();}public void setPeopleService( final PeopleService peopleService ) {this.peopleService = peopleService;} }我們可以看到,這里沒有任何關于OSGi的信息 。 唯一的依賴是在某種程度上應該被注入PeopleRestService的PeopleService。 怎么樣? 通常, OSGi應用程序使用藍圖作為依賴項注入框架,這與基于XML的老伙伴Spring配置非常相似。 它應該與應用程序一起打包在OSGI-INF / blueprint文件夾中。 這是在Apache CXF 3.0.1之上構建的REST模塊的藍圖示例:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"xmlns:cxf="http://cxf.apache.org/blueprint/core"xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsdhttp://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsdhttp://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsdhttp://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd"><cxf:bus id="bus"><cxf:features><cxf:logging/></cxf:features> </cxf:bus><jaxrs:server address="/api" id="api"><jaxrs:serviceBeans><ref component-id="peopleRestService"/></jaxrs:serviceBeans><jaxrs:providers><bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" /></jaxrs:providers></jaxrs:server><!-- Implementation of the rest service --><bean id="peopleRestService" class="com.example.jaxrs.PeopleRestService"><property name="peopleService" ref="peopleService"/></bean> <reference id="peopleService" interface="com.example.services.PeopleService" /> </blueprint>非常小而簡單:基本上,配置僅指出為了使模塊正常工作,應提供對com.example.services.PeopleService的引用(有效地由OSGi容器提供)。 為了了解它是如何發生的,讓我們看一下另一個公開服務的模塊。 它僅包含一個接口PeopleService :
package com.example.services;import java.util.Collection;import com.example.data.model.Person;public interface PeopleService {Collection< Person > getPeople( int page, int pageSize );Person getByEmail( final String email );Person addPerson( final String email, final String firstName, final String lastName );void removePerson( final String email ); }并提供其實現作為PeopleServiceImpl類:
package com.example.services.impl;import java.util.Collection;import org.osgi.service.log.LogService;import com.example.data.PeopleDao; import com.example.data.model.Person; import com.example.services.PeopleService;public class PeopleServiceImpl implements PeopleService {private PeopleDao peopleDao;private LogService logService;@Overridepublic Collection< Person > getPeople( final int page, final int pageSize ) { logService.log( LogService.LOG_INFO, "Getting all people" );return peopleDao.findAll( page, pageSize );}@Overridepublic Person getByEmail( final String email ) {logService.log( LogService.LOG_INFO, "Looking for a person with e-mail: " + email );return peopleDao.find( email ); }@Overridepublic Person addPerson( final String email, final String firstName, final String lastName ) {logService.log( LogService.LOG_INFO, "Adding new person with e-mail: " + email );return peopleDao.save( new Person( email, firstName, lastName ) );}@Overridepublic void removePerson( final String email ) {logService.log( LogService.LOG_INFO, "Removing a person with e-mail: " + email );peopleDao.delete( email );}public void setPeopleDao( final PeopleDao peopleDao ) {this.peopleDao = peopleDao;}public void setLogService( final LogService logService ) {this.logService = logService;} }這次又一次是非常小的,干凈的實現,它具有兩個可注入的依賴項org.osgi.service.log.LogService和com.example.data.PeopleDao 。 它的藍圖配置位于OSGI-INF / blueprint文件夾中,看起來也很緊湊:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"><service ref="peopleService" interface="com.example.services.PeopleService" /> <bean id="peopleService" class="com.example.services.impl.PeopleServiceImpl"><property name="peopleDao" ref="peopleDao" /> <property name="logService" ref="logService" /></bean><reference id="peopleDao" interface="com.example.data.PeopleDao" /><reference id="logService" interface="org.osgi.service.log.LogService" /> </blueprint>預期由OSGi容器在運行時提供對PeopleDao和LogService的引用。 但是, PeopleService的實現是作為服務公開的,并且一旦其捆綁包被激活, OSGi容器將能夠將其注入PeopleRestService 。
難題的最后一部分,數據訪問模塊,稍微復雜一點:它包含持久性配置( META-INF / persistence.xml ),并且基本上依賴于OSGi容器的JPA 2.0功能。 persistence.xml非?;?#xff1a;
<persistence xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"version="2.0"><persistence-unit name="peopleDb" transaction-type="JTA"><jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=peopleDb)</jta-data-source> <class>com.example.data.model.Person</class><properties><property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/> </properties> </persistence-unit> </persistence>與服務模塊類似, PeopleDao公開了一個接口:
package com.example.data;import java.util.Collection;import com.example.data.model.Person;public interface PeopleDao {Person save( final Person person );Person find( final String email );Collection< Person > findAll( final int page, final int pageSize );void delete( final String email ); }通過其實現PeopleDaoImpl :
package com.example.data.impl;import java.util.Collection;import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery;import com.example.data.PeopleDao; import com.example.data.model.Person;public class PeopleDaoImpl implements PeopleDao {private EntityManager entityManager;@Overridepublic Person save( final Person person ) {entityManager.persist( person );return person;}@Overridepublic Person find( final String email ) {return entityManager.find( Person.class, email );}public void setEntityManager( final EntityManager entityManager ) {this.entityManager = entityManager;}@Overridepublic Collection< Person > findAll( final int page, final int pageSize ) {final CriteriaBuilder cb = entityManager.getCriteriaBuilder();final CriteriaQuery< Person > query = cb.createQuery( Person.class );query.from( Person.class );return entityManager.createQuery( query ).setFirstResult(( page - 1 ) * pageSize ).setMaxResults( pageSize ) .getResultList();}@Overridepublic void delete( final String email ) {entityManager.remove( find( email ) );} }請注意,盡管我們正在執行數據操作,但是沒有提及事務,也沒有對實體管理器的事務API的顯式調用。 我們將使用聲明式方法進行事務處理,因為藍圖配置支持(位置不變, OSGI-INF / blueprint文件夾):
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.1.0"xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"><service ref="peopleDao" interface="com.example.data.PeopleDao" /><bean id="peopleDao" class="com.example.data.impl.PeopleDaoImpl"><jpa:context unitname="peopleDb" property="entityManager" /><tx:transaction method="*" value="Required"/></bean><bean id="dataSource" class="org.hsqldb.jdbc.JDBCDataSource"><property name="url" value="jdbc:hsqldb:mem:peopleDb"/></bean><service ref="dataSource" interface="javax.sql.DataSource"> <service-properties> <entry key="osgi.jndi.service.name" value="peopleDb" /> </service-properties> </service> </blueprint>要記住的一件事:應用程序不需要創建JPA 2.1的實體管理器: OSGi運行時能夠做到這一點,并將其注入到需要的地方,由jpa:context聲明驅動。 因此, tx:transaction指示運行時將選定的服務方法包裝在事務中。
現在,當提供最后一個服務PeopleDao時 ,我們準備使用Apache Karaf 3.0.1部署我們的模塊。 三個步驟很容易做到:
- 運行Apache Karaf 3.0.1容器 bin/karaf (or bin\karaf.bat on Windows)
- 從Apache Karaf 3.0.1 shell執行以下命令: feature:repo-add cxf 3.0.1 feature:install http cxf jpa openjpa transaction jndi jdbc install -s mvn:org.hsqldb/hsqldb/2.3.2 install -s mvn:com.fasterxml.jackson.core/jackson-core/2.4.0 install -s mvn:com.fasterxml.jackson.core/jackson-annotations/2.4.0 install -s mvn:com.fasterxml.jackson.core/jackson-databind/2.4.0 install -s mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/2.4.0 install -s mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/2.4.0
- 構建我們的模塊并將其復制到Apache Karaf 3.0.1的deploy文件夾(容器仍在運行時): mvn clean package cp module*/target/*jar apache-karaf-3.0.1/deploy/
在Apache Karaf 3.0.1 Shell中運行list命令時,應該看到所有激活的捆綁軟件(模塊)的列表,類似于以下列表:
  
 其中module-service , module-jax-rs和module-data對應于我們正在開發的模塊。 默認情況下,我們所有的Apache CXF 3.0.1服務將在基本URL http:// :8181 / cxf / api /上提供。 通過在Apache Karaf 3.0.1 shell中執行cxf:list-endpoints -f命令很容易檢查。 
讓我們通過發送幾個HTTP請求來確保REST層按預期工作。 讓我們創建一個新人:
curl http://localhost:8181/cxf/api/people -iX POST -d "firstName=Tom&lastName=Knocker&email=a@b.com"HTTP/1.1 201 Created Content-Length: 0 Date: Sat, 09 Aug 2014 15:26:17 GMT Location: http://localhost:8181/cxf/api/people/a@b.com Server: Jetty(8.1.14.v20131031)并驗證此人已成功創建:
curl -i http://localhost:8181/cxf/api/peopleHTTP/1.1 200 OK Content-Type: application/json Date: Sat, 09 Aug 2014 15:28:20 GMT Transfer-Encoding: chunked Server: Jetty(8.1.14.v20131031)[{"email":"a@b.com","firstName":"Tom","lastName":"Knocker"}]檢查數據庫是否也有人填充會很好。 使用Apache Karaf 3.0.1 shell,只需執行兩個命令即可輕松完成: jdbc:datasources和jdbc:query peopleDb“ select * from people” 。
太棒了! 我希望這篇介紹性很強的博客文章能打開另一篇有趣的技術,您可以將其用于開發健壯,可伸縮,模塊化和可管理的軟件。 我們沒有涉及很多東西,但是您可以在這里找到它們。 完整的源代碼可在GitHub上找到 。
Hibernate 4.2.x / 4.3.x用戶注意:不幸的是,在當前版本的Apache Karaf 3.0.1中 , Hibernate 4.3.x完全可以正常工作(因為尚不支持JPA 2.1 ),但是我設法做到了與Hibernate 4.2.x一起運行時,容器通常拒絕解析與JPA相關的依賴關系。
翻譯自: https://www.javacodegeeks.com/2014/08/osgi-the-gateway-into-micro-services-architecture.html
osgi架構與linux
總結
以上是生活随笔為你收集整理的osgi架构与linux_OSGi:进入微服务架构的门户的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 白眼表情是什么意思 白眼表情指的是什么
- 下一篇: 拳头游戏推出《英雄联盟》2023 全球总
