Titan Framework 項目部署

介紹

本文用來介紹Titan Framework的使用和下載, Titan Framework的多數據庫支持,各個微服務之間的調用,微服務的配置與部署。java

Titan Framework依賴包的下載跟使用

Titan Framework包能夠作在Titan Framework PaaS平臺上進行下載,提供各個版本。node

使用以下代碼把Titan Framework 包加到本地maven倉庫中:mysql

Echo move titan-framework-1.2.jarweb

        mvn install:install-file -Dfile=.\titan-framework-1.2.jar -DgroupId=org.titan.framework -DartifactId=titan-framework -Dversion=1.2.RELEASE -Dpackaging=jarredis

在微服務的pom文件中添加Titan Framework 包依賴:spring

    <properties>  sql

<titan.version>1.2.RELEASE</titan.version>數據庫

</properties>sass

 

<dependencies>服務器

<dependency>

<groupId>org.titan.framework</groupId>

<artifactId>titan-framework</artifactId>

<version>${titan.version}</version>

</dependency>

     </dependencies>

Titan Framework多服務的使用

Titan Framework 單個微服務結構圖:

在Titan Framework中,每一個微服務的核心工程結構分爲ControllerEntityEventLaunch

  1. Controller包中又能夠分割爲兩個具體邏輯組件,分別是具體實現API配置的Controller與進行接入層邏輯控制的Handler。對於Controller的Handler包,咱們建議將一些接入層的檢查放在這裏,例如Token有效性或者Json參數的格式驗證。
  2. Entity包主要是本微服務中使用到的數據對象實體定義。例如,傳統結構中的DTO定義就能夠放在Entity文件夾下。
  3. Event包是Titan微服務之間進行相互調用的入口,在Event文件夾下,咱們經常放置EventHandler,專門用來提供跨微服務的通信支持。例如,LoginService須要調用UserService進行用戶信息校驗。此時UserService就能夠提供一個VerifyUserInformationEvent的內部接口,用來和LoginService進行跨微服務協做。對於Event包,咱們建議將不少業務邏輯放在裏面。
  4. Launch包中主要是微服務啓動參數的配置與啓動器的配置。Titan Framework每一個微服務內置Jetty容器,使用時無需單獨部署其餘容器。在啓動時,Titan Framework的微服務直接經過相似Java Application的方式進行啓動,即Java -jar serice.jar。

在同臺服務器上使用Titan Framework中多個微服務,需建立application.properties文件,目錄\resources,由於Titan Framework中每一個微服務使用的都是默認端口7070

resources目錄以下:

application.properties文件:

server.port=8012

如未添加報以下錯誤:

org.springframework.boot.context.embedded.PortInUseException: Port 7070 is already in use

at org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainer.start(JettyEmbeddedServletContainer.java:131)

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(EmbeddedWebApplicationContext.java:297)

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:145)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)

at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)

at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175)

at org.titan.framework.facade.launcher.LauncherFrontend.ALLATORIxDEMO(ig:50)

at org.titan.framework.facade.launcher.LauncherFrontend.lunch(ig:161)

at org.titan.loginRegister.loginRegisterc.launch.LaunchLoginRegisterC.main(LaunchLoginRegisterC.java:14)

集羣使用還需修改**/project/conf/cluster.properties工具包

cluster.local.port端口不能相同

  1. cluster.system.name使用同一名稱;
  2. cluster.seeds默認本身,A,B,C同在一個集羣下;

A服務

cluster.system.name=TitanFrameworkSystem

cluster.local.port=1818

cluster.local.host=192.168.199.170

cluster.seeds=192.168.199.170:1818

B服務

cluster.system.name=TitanFrameworkSystem

cluster.local.port=2828

cluster.local.host=192.168.199.170

cluster.seeds=192.168.199.170:2828, 192.168.199.170:1818

C服務

cluster.system.name=TitanFrameworkSystem

cluster.local.port=3838

cluster.local.host=192.168.199.170

cluster.seeds=192.168.199.170:3838,192.168.199.170:1818

 

A,B,C,D四個微服務的項目,B,C,D三個微服務都去鏈接A服務,這樣就構建成一個集羣,在這個集羣中BCD之間是沒有鏈接的,可是他們都鏈接了A服務,因此他們之間也是能夠進行通訊的。

以下圖:

B,C,D鏈接A服務打印信息:

[INFO] [06/02/2018 13:07:50.781] [TitanFrameworkSystem-akka.actor.default-dispatcher-4] [akka.cluster.Cluster(akka://TitanFrameworkSystem)] Cluster Node [akka.tcp://TitanFrameworkSystem@192.168.199.170:1818] - Node [akka.tcp://TitanFrameworkSystem@192.168.199.170:2828] is JOINING, roles [worker]

[INFO] [06/02/2018 13:07:51.177] [TitanFrameworkSystem-akka.actor.default-dispatcher-2] [akka.cluster.Cluster(akka://TitanFrameworkSystem)] Cluster Node [akka.tcp://TitanFrameworkSystem@192.168.199.170:1818] - Leader is moving node [akka.tcp://TitanFrameworkSystem@192.168.199.170:2828] to [Up]

 

B,C,D斷開鏈接A服務打印信息:

[WARN] [06/02/2018 13:09:24.932] [New I/O worker #4] [NettyTransport(akka://TitanFrameworkSystem)] Remote connection to /192.168.199.170:52593 failed with java.io.IOException: 遠程主機強迫關閉了一個現有的鏈接。

[WARN] [06/02/2018 13:09:24.953] [TitanFrameworkSystem-akka.remote.default-remote-dispatcher-26] [akka.tcp://TitanFrameworkSystem@192.168.199.170:1818/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FTitanFrameworkSystem%40192.168.199.170%3A2828-0] Association with remote system [akka.tcp://TitanFrameworkSystem@192.168.199.170:2828] has failed, address is now gated for [5000] ms. Reason: [Disassociated]

[INFO] [06/02/2018 13:09:27.729] [TitanFrameworkSystem-akka.actor.default-dispatcher-2] [akka://TitanFrameworkSystem/deadLetters] Message [akka.cluster.pubsub.DistributedPubSubMediator$Internal$Status] from Actor[akka://TitanFrameworkSystem/system/distributedPubSubMediator#1184035447] to Actor[akka://TitanFrameworkSystem/deadLetters] was not delivered. [10] dead letters encountered, no more dead letters will be logged. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

[WARN] [06/02/2018 13:09:29.173] [TitanFrameworkSystem-akka.actor.default-dispatcher-5] [akka.tcp://TitanFrameworkSystem@192.168.199.170:1818/system/cluster/core/daemon] Cluster Node [akka.tcp://TitanFrameworkSystem@192.168.199.170:1818] - Marking node(s) as UNREACHABLE [Member(address = akka.tcp://TitanFrameworkSystem@192.168.199.170:2828, status = Up)]. Node roles [worker]

[WARN] [06/02/2018 13:09:31.268] [New I/O boss #3] [NettyTransport(akka://TitanFrameworkSystem)] Remote connection to null failed with java.net.ConnectException: Connection refused: no further information: /192.168.199.170:2828

[WARN] [06/02/2018 13:09:31.279] [TitanFrameworkSystem-akka.remote.default-remote-dispatcher-26] [akka.tcp://TitanFrameworkSystem@192.168.199.170:1818/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FTitanFrameworkSystem%40192.168.199.170%3A2828-0] Association with remote system [akka.tcp://TitanFrameworkSystem@192.168.199.170:2828] has failed, address is now gated for [5000] ms. Reason: [Association failed with [akka.tcp://TitanFrameworkSystem@192.168.199.170:2828]] Caused by: [Connection refused: no further information: /192.168.199.170:2828]

Titan FrameworkAPI的編寫

controller定義,系統默認接收Json body ,基於JsonToEntity模式進行對象轉換,調用方法以下:JsonParserFactory.getParser().getObject(body, TplAppEntity.class);

@RestController

@RequestMapping("/demoa")

public class ADemoController extends RestfulController {

    /** 系統默認HTTP POST方法**/

    @Override

    protected <T> Command<?> getCreateCommand(String service, T body) {

        String _body = (String) body;

        DemoAEntity entity = JsonParser.getObject(_body, DemoAEntity.class);

        return new Create<DemoAEntity>(entity);

    }

     /** 系統默認HTTP Delete方法**/

    @Override

    protected Command<?> getDeleteCommand(String service, String id) {

        DemoAEntity entity = new DemoAEntity();

        entity.setId(id);

        return new Delete<DemoAEntity>(entity);

    }

     /** 系統默認HTTP Get方法**/

    @Override

    protected Command<?> getGetCommand(String service, String arg1) {

        return null;

    }

     /** 系統默認HTTP Patch方法**/

    @Override

    protected Command<?> getPatchCommand(String arg0, String arg1, String arg2) {

        return null;

    }

    /** 系統默認HTTP Put方法**/

    @Override

    protected Command<?> getPutCommand(String arg0, String arg1, String arg2) {

        return null;

    }

    /** 系統默認query方法**/

    @Override

    protected Command<?> getQueryCommand(String arg0, Object arg1) {

        return null;

    }

}

 

Command Handler定義

Command Handler是用來響應API (Controller的部分的請求),基於類上的註解在啓動時自動完成handlerCommand的註冊過程。

@CmdHandler

public class DemoACreateHandler implements CommandHandler<Create<DemoAEntity>> {

    @Override

    public Result handle(Create<DemoAEntity> cmd) {

        DemoAEntity entity = cmd.getEntity();

        System.out.println(entity.getName() + "," + entity.getText());

        Result result = Publish.Send(Ways.Remote(Paths.DemoB.service.getServerName(),

        new DemoACreateEvent())).Retry();

        return result;

    }

}

 

Titan Framework的 Command模型

Titan Framework經過Command將Controller與對應的CommandHandler進行關聯。在上面的例子中,咱們能夠看到POST請求將會被getCreateCommand方法捕獲,捕獲後經過建立一個Create類型的Command將具體的請求內容提交到一個CommandHandler。

具體的綁定邏輯關鍵點在於Command類型以及Command中綁定的Entity類型。在上面的例子中,getCreateCommand提交了一個Create<DemoAEntity>的command。對應的CommandHandler(注意:必須經過@CmdHandler註釋進行標註,不然Titan Framework沒法有效識別)實現了一個CommandHandler<Create<DemoAEntity>>的接口。在這個狀況下,Titan Framework會在底層經過Create<DemoAEntity>這個Command類型完成Controller層與CommandHandler層的匹配。

做爲Titan Framework的高階用法,咱們在getCreateCommand中能夠經過serviceName(getCreateCommand有兩個參數,分別是serviceName與T body),分離出不一樣的分支,向多個不一樣的CommandHandler發送不一樣的Command。這一點,你們能夠在實際使用中進一步探索。

Titan Framework的微服務相互調用

在這裏,咱們假設有兩個Titan微服務,其中A微服務做爲API接入服務,B微服務做爲業務邏輯處理服務。

A微服務與B微服務之間的通信就是由上面說到的Event進行驅動。例如A能夠在Controller的Handler主鍵中調用遠程請求,將特定的Event發送給B微服務。B微服務經過EventHandler捕獲這個特定的遠程請求。

handler代碼以下:

@CmdHandler

public class LoginCreateHandler implements CommandHandler<Create<LoginEntity>> {

 

    @Override

    public Result handle(Create<LoginEntity> cmd) {

     LoginEntity entity = cmd.getEntity();

     LoginCreateEvent loginCreateEvent = new LoginCreateEvent();

     loginCreateEvent.setPhone(entity.getPhone());

     loginCreateEvent.setOtp(entity.getOtp());

        Result result = Publish.Send(Ways.Remote(Paths.LoginRegisterE.service.getServerName(), loginCreateEvent)).Retry();

        return result;

    }

}

 

B服務接收event代碼以下:

@EvtHandler(Role = "loginRegister", Service = "e")

public class CreateLoginEventHandler implements EventHandler<LoginCreateEvent> {

 

    @Override

    public void handle(LoginCreateEvent event) {

        String phone = event.getPhone();

        String otp = event.getOtp();

    }

}

Titan FrameworkDataSource的使用

Titan Framework提供了Repository包,集成了關係型與非關係型數據庫的驅動。

mysql

Respository集成

@Repository

public class DemoCRespository extends SpringMysqlRepository<CLoginRegisterEntity> {

 

    @Override

    protected String getTableName() {

        return "testentity";

    }

}

/project/conf/mysql.properties代碼:

#Database Configuration

df.db.driver=com.mysql.cj.jdbc.Driver

# for master

master.db.url=jdbc:mysql://127.0.0.1:3306/dbname?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=true

master.db.username=root

master.db.password=

# for slave

slave.db.url=jdbc:mysql://127.0.0.1:3306/dbname?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=true

slave.db.username=root

slave.db.password=

#jOOQ Configuration

 

MongoDB

Respository集成

@Repository

public class ProjectDetailsRespository implements StorageDataProcessor.Mongo {

 

@Override

public MongoDBConverter extConverter() {

// TODO Auto-generated method stub

return null;

}

public void insertUser(ProjectDetailsEntity projectDetails) {

Curd crud = curd();

crud.add(ProjectDetailsEntity.class.getSimpleName(), projectDetails);

}

public void addList(List<ProjectDetailsEntity> projectDetails) {

Curd crud = curd();

crud.add(ProjectDetailsEntity.class.getSimpleName(), projectDetails);

}

public List<ProjectDetailsEntity> queryList(String key,String value) {

Curd crud = curd();

List<ProjectDetailsEntity> list = new ArrayList<ProjectDetailsEntity>();

    list = crud.queryByCondition(MongoDBQueryCondition.Condition(query -> {

        query.Table(ProjectDetailsEntity.class.getSimpleName(), ProjectDetailsEntity.class).Condition(key, value);

    }));

    return list ;

}

}

 

/project/conf/mongoDB.properties代碼

 

mongo.host=127.0.0.1

mongo.port=27017

#mongo.host=192.168.10.135

#mongo.port=13131

#mongo.dbname=dbkita

#mongo.host=139.196.6.164

#mongo.port=32771

#mongo.host=47.91.145.54

#mongo.port=13131

mongo.dbname=titan-paas

 

Redis

Respository集成

@Repository

public class DemeoRepository extends SpringMysqlRepository<DemoEntity> implements StorageDataProcessor.Redis {

 

    @Override

    protected String getTableName() {

        return "DemoEntity";

    }

 

    public Result modify(DemoEntity entity) {

        QueryParams queryParams = new QueryParams.Builder().equal("Id").build();

        Map<String, Object> queryMap = new HashMap<String, Object>();

        queryMap.put("Id", entity.getId());

        return update(entity, queryParams, queryMap);

    }

}

/project/conf/redis.properties代碼

#最大分配的對象數  

jedisPool.maxActive=20  

#最大可以保持idel狀態的對象數  

jedisPool.maxIdle=20  

#最小可以保持idel狀態的對象數  

jedisPool.minIdle=10

#當池內沒有返回對象時,最大等待時間  

jedisPool.maxWait=-1

#當調用borrow Object方法時,是否進行有效性檢查  

#指明是否在從池中取出鏈接前進行檢驗,若是檢驗失敗,則從池中去除鏈接並嘗試取出另外一個

jedisPool.testOnBorrow=true  

#在return給pool時,是否提早進行validate操做

jedisPool.testOnReturn =false

#表示當pool中的jedis實例都被allocated完時,pool要採起的操做;

#默認有三種WHEN_EXHAUSTED_FAIL(表示無jedis實例時,直接拋出NoSuchElementException)、

#WHEN_EXHAUSTED_BLOCK(則表示阻塞住,或者達到maxWait時拋出JedisConnectionException)、

#WHEN_EXHAUSTED_GROW(則表示新建一個jedis實例,也就說設置的maxActive無用)

jedisPool.whenExhaustedAction=1 

#表示idle object evitor兩次掃描之間要sleep的毫秒數;

jedisPool.timeBetweenEvictionRunsMillis = 100000

#若是爲true,表示有一個idle object evitor線程對idle object進行掃描,若是validate失敗,此object會被從pool中drop掉;

#這一項只有在timeBetweenEvictionRunsMillis大於0時纔有意義;

jedisPool.testWhileIdle=true

#表示一個對象至少停留在idle狀態的最短期,而後才能被idle object evitor掃描並驅逐;

#這一項只有在timeBetweenEvictionRunsMillis大於0時纔有意義

jedisPool.minEvictableIdleTimeMillis=300000 

#在minEvictableIdleTimeMillis基礎上,加入了至少minIdle個對象已經在pool裏面了。

#若是爲-1,evicted不會根據idle time驅逐任何對象。若是minEvictableIdleTimeMillis>0,則此項設置無心義,

#且只有在timeBetweenEvictionRunsMillis大於0時纔有意義

jedisPool.softMinEvictableIdleTimeMillis = -1 

#表示idle object evitor每次掃描的最多的對象數

jedisPool.numTestsPerEvictionRun = 50  

#borrowObject返回對象時,是採用DEFAULT_LIFO(last in first out,即相似cache的最頻繁使用隊列),若是爲False,則表示FIFO隊列

jedisPool.lifo = true

#IP  

jedisPool.shard1.host=127.0.0.1 

#Port  

jedisPool.shard1.port=6379

#password

redis.password=

#客戶端超時時間單位是毫秒

redis.timeout=100000

#name

redis.name=queue

#database

redis.database=2

Titan Frameworklog日誌的使用

Titan Framework中使用的包是slf4j,須要把slf4j包配置pom文件中

 

pom文件配置以下

    <properties> 

<akka.version>2.4.19</akka.version>

</properties>

    <dependency>

<groupId>com.typesafe.akka</groupId>

<artifactId>akka-slf4j_2.11</artifactId>

<version>${akka.version}</version>

<scope>runtime</scope>

</dependency>

 

log日誌的使用:

@EvtHandler(Role = "loginRegister", Service = "e")

public class CreateLoginEventHandler implements EventHandler<LoginCreateEvent> {

 

private static final Logger logger = LoggerFactory.getLogger(CreateLoginEventHandler.class);

 

    @Override

    public void handle(LoginCreateEvent event) {

     logger.error("錯誤信息");

    }

 

}

 

Titan Framework的打包與服務器部署

Titan Framework的打包:

第一步在微服務的pom文件中添加以下代碼

 

<build>

<plugins>

<plugin>

<artifactId>maven-dependency-plugin</artifactId>

</plugin>

<plugin>

<artifactId>maven-assembly-plugin</artifactId>

<configuration>

<descriptorRefs>

<descriptorRef>deploy-backend-assembly</descriptorRef>

</descriptorRefs>

<appendAssemblyId>true</appendAssemblyId>

</configuration>

</plugin>

</plugins>

</build>

 

第二步:打開cmd,進入到項目目錄,運行命令mvn clean installcd {project_folder_location}:\MyEclipse10Workspace\demo\demo,運行命令mvn clean install。打包生成的文件會在target下生成.zip文件。

Titan Framework服務器部署:

第一步:把打包生成的.zip文件上傳至服務器解壓,把conf配置添加到解壓文件demoa-titandemo-1.0-SNAPSHOT-bin\demoa-titandemo-1.0-SNAPSHOT\conf路徑下。

如圖:

第二步:把微服務中的spring配置文件cope到\demoa-titandemo-1.0-SNAPSHOT路徑下。

 

第三步:修改conf目錄下cluster.properties文件裏的IP地址,修改爲服務器IP地址

第四步:java -jar **.jar 啓動服務,未報錯出現以下日誌服務啓動成功。

2018-06-02 16:32:53.103  INFO 26195 --- [           main] application                              : Initializing Spring FrameworkServlet 'dispatcherServlet'

2018-06-02 16:32:53.103  INFO 26195 --- [           main] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started

2018-06-02 16:32:53.119  INFO 26195 --- [           main] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 16 ms

2018-06-02 16:32:53.130  INFO 26195 --- [           main] o.e.jetty.server.AbstractConnector       : Started ServerConnector@693f2c89{HTTP/1.1,[http/1.1]}{0.0.0.0:7070}

2018-06-02 16:32:53.134  INFO 26195 --- [           main] .s.b.c.e.j.JettyEmbeddedServletContainer : Jetty started on port(s) 7070 (http/1.1)

2018-06-02 16:32:53.140  INFO 26195 --- [           main] o.t.l.l.launch.LaunchLoginRegistera      : Started LaunchLoginRegistera in 6.297 seconds (JVM running for 6.768)

相關文章
相關標籤/搜索