同步操作将从 yiyongfei/go-yea 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
使用go-yea前,请先下载yea,并且执行yea/pom.xml
mvn clean install -Dmaven.test.skip=true
GO-YEA是YEA的一个应用,它是一个快速启动分布式框架,致力于提供产品的快速启动以及后续的服务伸缩。 其核心部分包含:
系统伸缩性通常以三种方式完成:1、增加副本;2、功能分割;3、数据分割。YEA主要考虑前二种方式。
通过go-yea-launcher里配置的DefaultClient,以支持同JVM间Act相互调用
<bean id="launcherClient" class="com.yea.core.remote.client.DefaultClient" />
在go-yea-web里建立与go-yea-launcher的依赖关系,且将go-yea-launcher里的配置文件引入
<import resource="classpath:/application-launcher.xml" />
go-yea-launcher作为服务生产者对外提供服务。
<bean id="nettyServer" class="com.yea.remote.netty.server.NettyServer" />
go-yea-web作为服务消费者通过NettyClient远程调用服务生产者所提供的服务来完成业务操作(不依赖于go-yea-launcher)
<bean id="nettyClient" class="com.yea.remote.netty.client.NettyClient" />
基于产品线规划将go-yea-launcher拆分成go-yea-launcher-permission与go-yea-launcher-authorization,以二个不同的注册名向Zookeeper注册。
go-yea-web将建立二个Netty客户端分别与go-yea-launcher-permission与go-yea-launcher-authorization建立连接。
测试环境说明:三台Vultr的云主机,各1 CPU(单核),1024MB 内存,一台部署go-yea-web(Tomcat),一台部署Launcher(启三个服务,每个服务占用堆内存128MB),一台部署Jmeter用于测试。 测试软件:Jmeter。 测试请求:permission/operation/query。 测试结果: 详细数据: 详细结果 提升性能指标:可以考虑先适当增加CPU核数和内存容量,然后再横向扩充。 纵向扩展对比: 测试环境:二台Vultr的云主机,各2 CPU,4096MB 内存 测试请求:permission/operation/query。 测试结果(600并发): 详细数据: 600并发结果 500并发结果 700并发结果
执行go-yea/pom.xml:
mvn clean package -Dmaven.test.skip=true -Pdevelop
复制go-yea-web/target/go-yea-web.war到应用服务器部署目录内,启动服务器
参见单机模式
执行go-yea/pom.xml:
mvn clean package -Dmaven.test.skip=true
复制go-yea/go-yea-launcher/target/go-yea-launcher-0.0.1-release.tar.gz到执行目录
tar -xzvf go-yea-launcher-0.0.1-release.tar.gz;
cd launcher;
sh start.sh;
启动时会要求输入Netty服务端绑定端口,输入端口或直接回车
复制go-yea-web/target/go-yea-web.war到应用服务器部署目录内,启动服务器
RPC模式下,启动Web服务时会调用APP服务初始化Shiro权限管理信息,启动顺序先APP后WEB。实际应用中可单独部署一台APP用于提供统一认证授权服务。
向外部系统提供APP服务接口,服务内部实现具体的业务场景。可参照go-yea的结构建立Maven项目结构:
@Repository
public class CommonDao<T> extends AbstractBaseDAO<T> {
省略
}
<!-- JVM内调用,注意,DefaultClient需设置lazy为false,以确保向ClientRegister注册本地客户端 -->
<bean id="launcherClient" class="com.yea.core.remote.client.DefaultClient" lazy-init="false" init-method="connect" destroy-method="disconnect" ></bean>
<!-- JVM内调用,注意,DefaultClient需设置lazy为false,以确保向ClientRegister注册本地客户端 -->
<bean id="launcherClient" class="com.yea.core.remote.client.DefaultClient" lazy-init="false" init-method="connect" destroy-method="disconnect" ></bean>
<!-- Netty编解码的Handler实现 -->
<bean id="nettyMessageDecoder" class="com.yea.remote.netty.codec.NettyMessageDecoder"></bean>
<bean id="nettyMessageEncoder" class="com.yea.remote.netty.codec.NettyMessageEncoder"></bean>
<!-- Netty心跳检测Handler实现 -->
<bean id="heartBeatServerHandler" class="com.yea.remote.netty.server.handle.HeartBeatServerHandler">
<constructor-arg index="0" type="int" value="60"/>
<constructor-arg index="1" type="int" value="60"/>
</bean>
<!-- Netty服务处理Handler实现,所有业务操作均由该Handler处理 -->
<bean id="serviceServerHandler" class="com.yea.remote.netty.server.handle.ServiceServerHandler"></bean>
<!-- Netty异常处理Handler实现,Netty处理时若抛出异常,由该Handler封装异常并返回调用端 -->
<bean id="exceptionHandler" class="com.yea.remote.netty.handle.ExceptionHandler"></bean>
<!-- Zookeeper调度中心的配置 -->
<bean id="zkDispatcher" class="com.yea.dispatcher.zookeeper.ZookeeperDispatcher" init-method="init">
<property name="host" value="${zookeeper.host}" />
<property name="port" value="${zookeeper.port}" />
</bean>
<!-- Netty服务端配置,Netty服务启动将在Main内调用(外部提供服务绑定端口),启动服务后向调度中心发送服务注册请求 -->
<bean id="nettyServer" class="com.yea.remote.netty.server.NettyServer" destroy-method="shutdown">
<property name="registerName" value="${netty.server.register}" /><!-- 服务注册名,将在Zookeeper内注册 -->
<property name="dispatcher" ref="zkDispatcher" />
<property name="host" value="${netty.server.host}" /><!-- 该主机未设置时,系统将会读取本机IP自动设入 -->
<property name="port" value="${netty.server.port}" /><!-- 该端口在执行start.sh脚本时,允许外部输入并替换 -->
<property name="listHandler">
<list>
<map>
<entry key="MessageDecoder">
<ref bean="nettyMessageDecoder"/>
</entry>
</map>
<map>
<entry key="MessageEncoder">
<ref bean="nettyMessageEncoder"/>
</entry>
</map>
<map>
<entry key="HeartBeatHandler">
<ref bean="heartBeatServerHandler"/>
</entry>
</map>
<map>
<entry key="ServiceHandler">
<ref bean="serviceServerHandler"/>
</entry>
</map>
<map>
<entry key="ExceptionHandler">
<ref bean="exceptionHandler"/>
</entry>
</map>
</list>
</property>
</bean>
<!-- Netty服务端的配置 End -->
进入开发管理->生成工具
APP服务对外暴露的接口,客户端请求服务端时需提供Act名,Netty服务端收到请求后根据Act名找到相应的Bean并执行
@Service
public class QueryOperationAct extends AbstractAct {
protected Object perform(Object[] messages) throws Throwable {
省略
}
}
@Service
public class SaveOperationAct extends AbstractTransactionAct {
protected Object perform(Object[] messages) throws Throwable {
省略
}
}
提供Web服务,主要完成参数封装、页面展示。可参照go-yea的结构建立Maven项目结构:
<profile>
<!-- 单机模式 -->
<id>standalone</id>
<properties>
<profiles.active>standalone</profiles.active>
</properties>
<dependencies>
<dependency>
<groupId>com.team</groupId>
<artifactId>go-yea-launcher</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</profile>
<profile>
<!-- RPC模式 -->
<id>rpc</id>
<properties>
<profiles.active>rpc</profiles.active>
</properties>
<dependencies>
<dependency>
<groupId>com.yea</groupId>
<artifactId>yea-dispatcher</artifactId>
</dependency>
</dependencies>
</profile>
<import resource="classpath:/application-launcher.xml" />
<!-- Netty编解码的Handler实现 -->
<bean id="nettyMessageDecoder" class="com.yea.remote.netty.codec.NettyMessageDecoder"></bean>
<bean id="nettyMessageEncoder" class="com.yea.remote.netty.codec.NettyMessageEncoder"></bean>
<!-- Netty异常处理Handler实现,Netty处理时若抛出异常,由该Handler封装异常并返回调用端 -->
<bean id="exceptionHandler" class="com.yea.remote.netty.handle.ExceptionHandler"></bean>
<!-- Netty心跳检测Handler实现 -->
<bean id="heartBeatClientHandler" class="com.yea.remote.netty.client.handle.HeartBeatClientHandler">
<constructor-arg index="0" type="int" value="60"/>
<constructor-arg index="1" type="int" value="60"/>
</bean>
<!-- Netty客户端收到服务端响应后的处理Handler实现 -->
<bean id="serviceClientHandler" class="com.yea.remote.netty.client.handle.ServiceClientHandler"></bean>
<!-- Netty服务处理Handler实现,所有业务操作均由该Handler处理,配置该Handle是为了支持双向调用,由服务端主动发起请求,如果发送的动作均由客户端发起,该Handle可以不配置在客户端内 -->
<bean id="serviceServerHandler" class="com.yea.remote.netty.server.handle.ServiceServerHandler"></bean>
<!-- 调度中心的配置 -->
<bean id="zkDispatcher" class="com.yea.dispatcher.zookeeper.ZookeeperDispatcher" init-method="init">
<property name="host" value="${zookeeper.host}" />
<property name="port" value="${zookeeper.port}" />
</bean>
<!-- Netty客户端配置,启动时将会根据服务注册名主动连接服务端 -->
<bean id="nettyClient" class="com.yea.remote.netty.client.NettyClient" init-method="connect" destroy-method="disconnect">
<property name="registerName" value="${netty.server.register}" /><!-- 服务注册名 -->
<property name="dispatcher" ref="zkDispatcher" />
<property name="host" value="${netty.client.host}" /><!-- 该主机未设置时,系统将会读取本机IP自动设入 -->
<property name="port" value="${netty.client.port}" /><!-- 该端口在执行start.sh脚本时,允许外部输入并替换 -->
<property name="listHandler">
<list>
<map>
<entry key="MessageDecoder">
<ref bean="nettyMessageDecoder"/>
</entry>
</map>
<map>
<entry key="MessageEncoder">
<ref bean="nettyMessageEncoder"/>
</entry>
</map>
<map>
<entry key="HeartBeatHandler">
<ref bean="heartBeatClientHandler"/>
</entry>
</map>
<map>
<entry key="ServiceClientHandler">
<ref bean="serviceClientHandler"/>
</entry>
</map>
<map>
<entry key="ServiceServerHandler">
<ref bean="serviceServerHandler"/>
</entry>
</map>
<map>
<entry key="ExceptionHandler">
<ref bean="exceptionHandler"/>
</entry>
</map>
</list>
</property>
</bean>
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="JEA_SESSIONID"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="-1"/> <!-- maxAge=-1,表示浏览器关闭时失效此Cookie -->
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="1800000"/>
<property name="deleteInvalidSessions" value="true"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionDAO" ref="sessionDAO"/>
<property name="sessionIdCookieEnabled" value="true"/>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
<!-- rememberMe的Cookie模板 -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="604800"/><!-- 记住我的Cookie,保存时长7天 -->
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('9AVvhnFLuS3KTV8KprsdAg==')}" />
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<bean id="securityManager" class="com.yea.shiro.web.mgt.WebSecurityManager">
<property name="endpoint" ref="nettyClient"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.html"/>
<property name="successUrl" value="/index.html"/>
<property name="unauthorizedUrl" value="/unauthorized.html"/>
</bean>
<!-- 对ShiroWeb过滤器进行包装,以初始化过滤器链(不允许延迟加载) -->
<bean id="shiroFilterWrapper" class="com.yea.shiro.web.wrapper.ShiroFilterWrapper" init-method="init" lazy-init="false" >
<property name="endpoint" ref="nettyClient"/>
<property name="shiroFilter" ref="shiroFilter"/>
<property name="authenticedUrl" value="/authenticed.html"/>
<property name="logoutUrl" value="/logout.html"/>
</bean>
<!-- Shiro生命周期处理器-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- Redis池 -->
<bean id="redisGeneralPool" class="com.yea.cache.jedis.pool.RedisGeneralPool" init-method="initPool" destroy-method="destroyPool">
<property name="server" value="${redis.server}"/>
</bean>
<!-- RedisSessionDAO的支持,将Session放置在Redis服务上,可解决多Web服务器的Session同步问题 -->
<bean id="sessionDAO" class="com.yea.shiro.session.mgt.redis.ShiroSessionDAO">
<property name="cachePool" ref="redisGeneralPool"/>
</bean>
<mvc:interceptors>
<bean class="com.yea.shiro.web.interceptor.ShiroInterceptor"></bean>
</mvc:interceptors>
CallAct act = new CallAct();
act.setActName("queryOperationAct");
Promise<List<OperationInfo>> promise = ClientRegister.<List<OperationInfo>>getInstance().send(act);
CallAct act = new CallAct();
act.setActName("saveOperationAct");
Promise<List<OperationInfoPK>> promise = ClientRegister.<List<OperationInfoPK>>getInstance().send(act, operationDto);
CallAct act = new CallAct();
act.setActName("saveResourceIdentifierAct");
Promise<ResourceIdentifierPK> promise = ClientRegister.<ResourceIdentifierPK>getInstance().send(act, identifier, resourceId, operationId);
CallAct act = new CallAct();
act.setActName("重ActName");
Promise<ResourceIdentifierPK> promise = ClientRegister.<ResourceIdentifierPK>getInstance().send("LAUNCHER", act, identifier, resourceId, operationId);
List<OperationInfo> listOperation = promise.awaitObject(10000);
@Autowired
private AbstractEndpoint nettyClient;
CallAct act = new CallAct();
act.setActName("queryOperationAct");
Promise<List<OperationInfo>> promise = nettyClient.send(act);
对于历史项目,通过反射调用机制(ReflectAct,有事务控制)提供RPC的兼容性,调用方的使用方式上与之前比较类似
CallReflect act = new CallReflect();
act.setActName("authorizationService");
act.setMethodName("addRolePermission");
Promise<?> promise = ClientRegister.getInstance().send("LAUNCHER", act, roleId, resourceId, operationId);
若新添加的功能允许匿名用户访问,不需做任何授权配置即可,默设Shiro的Web访问控制是匿名访问,研发人员也可以在资源标识设置里配置Web访问是匿名访问。
若新添加的功能需要用户登录才能访问,需要研发人员在资源标识设置(权限管理->资源标识设置)里配置该Web资源的访问控制为基于用户或登录验证。
若新添加的功能需要授予用户权限后才能访问,此时:
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。