Java应用工程结构 – CN.programmer.Luxh

首页   /   新闻资讯   /   正文

分层的本质是关注点分离,隔离对下层的变化,可以简化复杂性,使得层次结构更加清晰。

1. 主流分层结构介绍

目前业界存在两种主流的应用工程结构:一种是阿里推出的《Java开发手册》中推荐的,另外一种是基于DDD(领域驱动设计)推荐的。

1.1 基于阿里《Java开发手册》的分层结构

Java应用工程结构 - CN.programmer.Luxh

• 开放 API 层:可直接封装 Service 接口暴露成 RPC 接口;通过 Web 封装成 http 接口;网关控制层等。 • 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染,JSP 渲染,移 动端展示等。 • Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。  • Service 层:相对具体的业务逻辑服务层。  • Manager 层:通用业务处理层,它有如下特征: 1) 对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。 2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。 3) 与 DAO 层交互,对多个 DAO 的组合复用。  • DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。  • 第三方服务:包括其它部门 RPC 服务接口,基础平台,其它公司的 HTTP 接口,如淘宝开放平台、支 付宝付款服务、高德地图服务等。 • 外部数据接口:外部(应用)数据存储服务提供的接口,多见于数据迁移场景中。

1.2 基于DDD(领域驱动设计)的分层结构

Java应用工程结构 - CN.programmer.Luxh

• 领域层:体现业务逻辑。 • 应用层:依赖领域层,根据业务对下层领域进行聚合和编排。 • 基础设施层:为其他提供技术支持。 • 用户接口层:为外部用户访问底层系统提供交互界面和数据表示。

2. 自己的工程结构

基于上述两种工程结构,设计一个适合自己的Java项目分层结构。

example └─src     ├─main     │  ├─java     │  │  └─com     │  │      └─example     │  │          ├─application                 --应用层(聚合多个领域)     │  │          ├─domain                      --领域层     │  │          │  ├─order                      --订单域     │  │          │  │  ├─bo                        --业务对象     │  │          │  │  ├─constant                  --领域内局部常量     │  │          │  │  ├─controller                --控制器     │  │          │  │  ├─dto                       --数据传输对象     │  │          │  │  ├─event                     --事件     │  │          │  │  │  ├─publish                  --发布     │  │          │  │  │  └─subscribe                --订阅     │  │          │  │  ├─manager                   --通用逻辑处理     │  │          │  │  ├─repository                --存储     │  │          │  │  │  ├─entity                   --实体,对应数据库中的字段     │  │          │  │  │  └─mapper                   --mybatis mapper     │  │          │  │  └─service                   --业务层处理     │  │          │  │      └─impl                    --业务接口实现     │  │          │  └─user                       --用户域     │  │          │      ├─bo     │  │          │      ├─constant     │  │          │      ├─controller     │  │          │      ├─dto     │  │          │      ├─event     │  │          │      │  ├─publish     │  │          │      │  └─subscribe     │  │          │      ├─manager     │  │          │      ├─repository     │  │          │      │  ├─entity     │  │          │      │  └─mapper     │  │          │      └─service     │  │          │          └─impl     │  │          └─infrastructure             --基础设施层     │  │              ├─config                   --配置     │  │              ├─constant                 --全局常量     │  │              ├─handler                  --处理器     │  │              ├─interceptor              --拦截器     │  │              ├─thirdparty               --第三方     │  │              └─utils                    --工具类     │  └─resources             │      ├─mapper     │      │  ├─order     │      │  └─user     │           │           │           └─test         └─java             └─com                 └─example
  • 接收参数和响应报文,请求以Req为后缀,响应以Resp为后缀,代码写在dto包中,比如创建订单请求和响应
/**  * 创建订单请求  */ @Data public class OrderCreateReq {      /**      * 用户id      */     private String userId;      /**      * 订单金额      */     private BigDecimal amount;      /**      * 下单的商品集合      */     private List<OrderDetailReq> orderDetailReqList;      @Data     public static class OrderDetailReq {          /**          * 商品id          */         private Long goodsId;         /**          * 商品数量          */         private Integer goodsNum;      } }   /**  * 创建订单响应  */ @Data public class OrderCreateResp {      /**      * 订单id      */     private String orderId; }
  • DAO层代码放在repository中
    Java应用工程结构 - CN.programmer.Luxh

  • 业务层代码放在service和manager中,比如创建订单因为涉及到订单表和订单明细表,需要在一个事务中,所以将事务代码下沉到manager。
    Java应用工程结构 - CN.programmer.Luxh

@Service public class OrderServiceImpl implements OrderService {      @Resource     private OrderManager orderManager;      @Override     public OrderCreateResp create(OrderCreateReq req) {          Order order = buildOrder(req);         List<OrderDetail> orderDetailList = buildOrderDetailList(order.getOrderId(), req);          orderManager.createOrder(order, orderDetailList);          OrderCreateResp resp = new OrderCreateResp();         resp.setOrderId(order.getOrderId());         return resp;     }       private Order buildOrder(OrderCreateReq req) {         Order order = new Order();         order.setOrderId(UUID.randomUUID().toString());         order.setUserId(req.getUserId());         order.setAmount(req.getAmount());         return order;     }       private List<OrderDetail> buildOrderDetailList(String orderId, OrderCreateReq req) {         List<OrderDetail> orderDetailList = new ArrayList<>();         for (OrderCreateReq.OrderDetailReq orderDetailReq : req.getOrderDetailReqList()) {             OrderDetail orderDetail = new OrderDetail();             orderDetail.setOrderId(orderId);             orderDetail.setGoodsId(orderDetailReq.getGoodsId());             orderDetail.setGoodsNum(orderDetailReq.getGoodsNum());             orderDetailList.add(orderDetail);         }         return orderDetailList;     } }
@Component public class OrderManager {      @Resource     private OrderMapper orderMapper;      @Resource     private OrderDetailMapper orderDetailMapper;      @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)     public void createOrder(Order order, List<OrderDetail> orderDetailList) {         orderMapper.insert(order);         for (OrderDetail orderDetail : orderDetailList) {             orderDetailMapper.insert(orderDetail);         }     }   }
  • 业务对象存放在bo包中,比如查询用户信息,不需要返回密码字段,则可以定义一个UserBO。
    Java应用工程结构 - CN.programmer.Luxh
@Data public class UserBO {          private String userId;          private String username;          private String nickname; }
  • application层做聚合编排,比如下单,既要保存订单信息,又要扣减库存,就需要对订单域和库存域进行聚合编排。