Titan Framework 项目部署

介绍

本文用来介绍Titan Framework的使用和下载, Titan Framework的多数据库支持,各个微服务之间的调用,微服务的配置与部署。

Titan Framework依赖包的下载跟使用

Titan Framework包可以做在Titan Framework PaaS平台上进行下载,提供各个版本。

使用如下代码把Titan Framework 包加到本地maven仓库中:

Echo move titan-framework-1.2.jar

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

在微服务的pom文件中添加Titan Framework 包依赖:

    <properties>  

<titan.version>1.2.RELEASE</titan.version>

</properties>

<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。对于ControllerHandler包,我们建议将一些接入层的检查放在这里,例如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://[email protected]:1818] - Node [akka.tcp://[email protected]: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://[email protected]:1818] - Leader is moving node [akka.tcp://[email protected]: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://[email protected]:1818/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FTitanFrameworkSystem%40192.168.199.170%3A2828-0] Association with remote system [akka.tcp://[email protected]: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://[email protected]:1818/system/cluster/core/daemon] Cluster Node [akka.tcp://[email protected]:1818] - Marking node(s) as UNREACHABLE [Member(address = akka.tcp://[email protected]: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://[email protected]:1818/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FTitanFrameworkSystem%40192.168.199.170%3A2828-0] Association with remote system [akka.tcp://[email protected]:2828] has failed, address is now gated for [5000] ms. Reason: [Association failed with [akka.tcp://[email protected]: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通过CommandController与对应的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中可以通过serviceNamegetCreateCommand有两个参数,分别是serviceNameT body),分离出不同的分支,向多个不同的CommandHandler发送不同的Command。这一点,大家可以在实际使用中进一步探索。

Titan Framework的微服务相互调用

在这里,我们假设有两个Titan微服务,其中A微服务作为API接入服务,B微服务作为业务逻辑处理服务。


A微服务与B微服务之间的通讯就是由上面说到的Event进行驱动。例如A可以在ControllerHandler主键中调用远程请求,将特定的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  

#returnpool时,是否提前进行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会被从pooldrop掉;

#这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

jedisPool.testWhileIdle=true

#表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;

#这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义

jedisPool.minEvictableIdleTimeMillis=300000 

#minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。

#如果为-1evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,

#且只有在timeBetweenEvictionRunsMillis大于0时才有意义

jedisPool.softMinEvictableIdleTimeMillis = -1 

#表示idle object evitor每次扫描的最多的对象数

jedisPool.numTestsPerEvictionRun = 50  

#borrowObject返回对象时,是采用DEFAULT_LIFOlast 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)

猜你喜欢

转载自blog.csdn.net/Titan_Framework/article/details/80844282