Java后端架构开荒实战(二)——单机到集群
一、前言
上一篇文章做了一些准备工作,这边文章正式开始写代码。
在做好单实例架构之后,升级到集群是一件很容易的事情,所以把单机和集群放在这一篇一起说。
二、单体项目架构
在开始前先说一下本文一些名词的定义吧。
组织(org):这个就是公司的意思,一个公司组织下面可能会有多个项目。
项目(project):项目在内部是要自洽的,项目和项目的调用之间就属于第三方调用了。比如本文提到的电商后端就是一个项目,组织公共类库就属于另外一个项目,每个项目有自己的生命周期。
应用(application):应用一般是一个领域服务的形式,在单体应用中可能是一个业务模块,在微服务架构中可能是一个微服务。
2.1 组织公共类库
这种二方库一般是公司组织级别的,就是封装了所有项目都可能用到的公共方法、配置和工具类等等,注意区别与项目里面的公共类库,这些类库的设计要注意通用性。
一些项目级别的专有配置和工具就不要放到这里来啦。
可以按照springboot源码那样按maven模块组织,也可以简单一点只分包吧。
贴一下web方面经常需要的配置:
统一返回结果BaseResult,一个通用的用接口层的范型返回对象是非常重要的。
public class BaseResult<T> {
/**
* 返回状态
*/
private boolean success;
/**
* 返回状态码
*/
private String code;
/**
* 返回信息
*/
private String message;
/**
* 返回数据
*/
private T data;
...
跨域配置,注意这里@ConditionalOnWebApplication web应用才生效。
/**
* <p>
* 跨域配置
* </p>
*
* @author robbendev
*/
@ConditionalOnWebApplication
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否发送Cookie信息
config.setAllowCredentials(true);
//放行哪些原始域(请求方式)
config.addAllowedMethod("*");
//放行哪些原始域(头部信息)
config.addAllowedHeader("*");
config.setMaxAge(3600L);
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
config.addExposedHeader("Content-Type");
config.addExposedHeader("X-Requested-With");
config.addExposedHeader("accept");
config.addExposedHeader("Origin");
config.addExposedHeader("Access-Control-Request-Method");
config.addExposedHeader("Access-Control-Request-Headers");
//2.添加映射路径
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
通用业务异常,web应用的一般在业务层抛出手动抛出,由全局异常捕获转然后转化成通用返回值返回。
/**
* 通用业务异常
*
* @author robbendev
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BizException extends RuntimeException implements Serializable {
/**
* 序列化
*/
private static final long serialVersionUID = -4636716497382947499L;
/**
* 错误码
*/
private String code;
/**
* 错误信息
*/
private String message;
/**
* 错误详情
*/
private Object data;
}
备份流 (RequestBakRequestWrapper就不贴了),拦截器那里会用到。
/**
* 对request请求进行包装备份请求参数
*
* @author robbendev
*/
@ConditionalOnWebApplication
@Component
@ServletComponentScan
@WebFilter(filterName = "requestBakFilter")
public class RequestBakFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletRequest = (HttpServletRequest) request;
RequestBakRequestWrapper requestWrapper = new RequestBakRequestWrapper(servletRequest);
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
}
}
其他的配置各个公司的最佳实践不一而同。
2.2 项目公共类库
这种公共类库是项目级别的,每个不同的项目会有项目内部的自定义公用类库需求。
如果你需要web开发就需要springboot-web诸如此类,这些就定义在这里。
项目依赖
shop-common/pom/xml
<parent>
<groupId>com.robbendev</groupId>
<artifactId>robbendev-shop-backend</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>shop-common</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<