描述用于Java Web应用程序的体系结构?
让我们分享基于Java的Web应用程序体系结构!
对于要使用Java实现的Web应用程序,有许多不同的体系结构。 这个问题的答案可以作为各种networking应用程序devise的优点和缺点。 虽然我意识到答案是主观的,但我们尽量客观,激励我们列出的利弊。
使用您喜欢的细节级别来描述您的架构。 为了您的答案具有任何价值,您至less必须描述您所描述的架构中使用的主要技术和思想。 最后但并非最不重要的是,我们什么时候应该使用你的架构
我会开始…
架构概述
我们使用基于Sun开放标准的三层体系结构,如Java EE,Java持久性API,Servlet和Java Server Pages。
- 坚持
- 商业
- 介绍
层之间可能的通信stream量表示为:
Persistence <-> Business <-> Presentation
例如,这意味着表示层从不调用或执行持久性操作,它始终通过业务层完成。 这种架构旨在满足高可用性Web应用程序的需求。
坚持
执行创build,读取,更新和删除( CRUD )持久性操作。 在我们的例子中,我们使用( Java持久性API )JPA,我们目前使用Hibernate作为持久性提供者并使用它的EntityManager 。
这个层被分成多个类,每个类处理某种types的实体(即与购物车相关的实体可能会被一个持久化类处理),并且被一个且只有一个pipe理器使用 。
此外,这个层还存储JPA实体 ,如Account
, ShoppingCart
等。
商业
所有绑定到Web应用程序function的逻辑都位于此图层中。 这种function可能会启动一个客户谁想要支付使用他/他的信用卡在线产品的资金转移。 这也可能是创build一个新的用户,删除一个用户或计算基于Web的游戏战斗的结果。
这个层被分成多个类,每个这些类都用@Stateless注解成为无状态会话Bean (SLSB)。 每个SLSB被称为经理 ,例如经理可以是一个被称为AccountManager
注解类。
当AccountManager
需要执行CRUD操作时,它将对持久层中的类AccountManagerPersistence
的实例进行适当的调用。 AccountManager
中两个方法的粗略草图可能是:
... public void makeExpiredAccountsInactive() { AccountManagerPersistence amp = new AccountManagerPersistence(...) // Calls persistence layer List<Account> expiredAccounts = amp.getAllExpiredAccounts(); for(Account account : expiredAccounts) { this.makeAccountInactive(account) } } public void makeAccountInactive(Account account) { AccountManagerPersistence amp = new AccountManagerPersistence(...) account.deactivate(); amp.storeUpdatedAccount(account); // Calls persistence layer }
我们使用容器pipe理器事务,所以我们不必做我们自己的事务划分。 基本上发生的是我们在进入SLSB方法时启动事务并在退出方法之前立即提交(或回滚)。 这是约定优于configuration的一个例子,但是我们并不需要除默认的Required之外的任何东西。
以下是Sun的Java EE 5教程如何解释Enterprise JavaBeans(EJB) 所需的事务属性 :
如果客户端在事务中运行并调用企业bean的方法,则该方法在客户端的事务中执行。 如果客户端未与事务关联,则在运行该方法之前,容器将启动新的事务。
Required属性是所有使用容器pipe理的事务分界运行的企业bean方法的隐式事务属性。 除非需要重写另一个事务属性,否则通常不要设置Required属性。 由于事务属性是声明性的,所以以后可以轻松更改它们。
介绍
我们的expression层负责…介绍! 它负责用户界面,并通过构buildHTML页面和通过GET和POST请求接收用户input来向用户显示信息。 我们正在使用旧的Servlet的+ Java服务器页面( JSP )组合。
该层调用业务层的pipe理者中的方法来执行用户请求的操作并接收要在网页中显示的信息。 有时,从业务层接收到的信息不像String
和int
egers那样复杂,有时候是JPA实体 。
与架构的优点和缺点
优点
- 让所有与在此层中执行持久性的特定方式相关的所有内容仅意味着我们可以从使用JPA切换到其他任何东西,而无需在业务层中重写任何内容。
- 我们很容易将我们的表示层转换成其他的东西,如果我们find更好的东西,我们很可能会这样做。
- 让EJB容器pipe理事务边界是很好的。
- 使用Servlet的+ JPA很容易(从一开始),这些技术在很多服务器中被广泛使用和实现。
- 使用Java EE应该使我们更容易创build具有负载平衡和故障转移function的高可用性系统。 这两个我们都觉得我们必须拥有。
缺点
- 使用JPA,可以通过在JPA实体类上使用
@NamedQuery
注释将经常使用的查询存储为命名查询。 如果您尽可能多地关注持久化类中的持久性,就像在我们的体系结构中一样,这将分散您可能发现查询以包括JPA实体的位置。 对持久性操作进行概述将更加困难,因此难以维护。 - 我们有JPA实体作为持久层的一部分。 但是
Account
和ShoppingCart
,他们不是真正的业务对象吗? 这样做是因为您必须触摸这些类并将其转换为JPA知道如何处理的实体。 - JPA实体(也是我们的业务对象)创build为数据传输对象( DTO ),也称为值对象(VO)。 这导致了贫血的领域模型,因为业务对象除了存取方法之外没有自己的逻辑。 所有的逻辑都是由业务层的pipe理者完成的,这导致了更程序化的编程风格。 这不是很好的面向对象的devise,但也许这不是一个问题? (所有的面向对象并不是唯一可以提供结果的编程范例。)
- 使用EJB和Java EE引入了一些复杂性。 而且我们不能使用纯粹的Tomcat(添加一个EJB微容器不是纯粹的 Tomcat)。
- 使用Servlet的+ JPA有很多问题。 使用Google获取有关这些问题的更多信息。
- 由于事务在退出业务层时是closures的,因此我们无法从JPA实体中加载任何信息,这些信息在表示层内部需要时(使用
fetch=FetchType.LAZY
)被configuration为从数据库加载。 它会触发一个例外。 在返回包含这些types字段的实体之前,我们必须确保调用相关的getter。 另一种select是使用Java持久性查询语言( JPQL )并执行FETCH JOIN
。 不过这两个选项都有点麻烦。
好吧,我会做一个(更短)一个:
- 前端: 挂毯 (3个旧项目,5个新项目)
- 业务层:Spring
- DAO的:Ibatis
- 数据库:Oracle
我们使用Sping事务支持,并在进入服务层时启动事务,传播到DAO调用。 服务层拥有最多的模型知识,而DAO则做了比较简单的CRUD工作。
由于性能原因,一些更复杂的查询内容由后端更复杂的查询处理。
在我们的例子中使用Spring的好处是我们可以拥有Spring代理类背后的国家/语言依赖实例。 根据会话中的用户,在进行呼叫时使用正确的国家/语言实施。
事务pipe理几乎是透明的,在运行时exception回滚。 我们尽可能使用未经检查的exception。 我们曾经做过检查exception,但是随着Spring的引入,我看到了非检查exception的好处,只有在可以的时候才处理exception。 它避免了许多样板“catch / rethrow”或“扔”的东西。
对不起,它比你的文章短,希望你find这个有趣的…
理想的基于Java的Web开发技术。
Web层:
HTML + CSS + Ajax的+ JQuery的
RESTFul Web控制器/动作/请求处理层:
Play框架
业务逻辑/服务层:
尽可能使用纯Java代码。 我们可以在这里完成Web服务的融合。
XML / JSon数据转换层:
XMLTool(谷歌代码search),JSoup,谷歌GSon,XStream,JOOX(Google代码search)
持久层:
CRUD:JPA或SienaProject或QueryDSL /复杂查询:JOOQ,QueryDSL
这是我的5美分
介绍
Android,Angular.JS WebClient,OAUTHv2
API
REST,Jersey(JAX-RS),Jackson(JSON去序列化),DTO对象(与业务逻辑模型不同)
商业逻辑
DI和事件处理的spring。 模型对象的DDD-ish方法。 更长时间的运行作业在工作模块中被SQS卸载。
DAO
使用Spring JDBC模板存储实体的存储库模型。 Redis(JEDIS)用于排行榜,使用Ordered列表。 令牌存储的Memcache。
数据库
MySQL,Memcached,Redis
我们在项目中遵循的是:
前端技术
- AngularJS
- HTML5
- CSS3
- 使用Javascript
- Bootstrap 3
API
- rest
- JERSEY(JAX-RS)
- 放心
- 弹簧
- jackson
- spring的安全
商业逻辑
-
spring的数据
-
SPRING数据MongoDB
数据库
- MongoDB的
服务器(用于caching)
- Redis的
我们仍然使用通常的Struts-Spring-Hibernate堆栈。
对于未来的应用程序,我们正在研究Flex前端的Spring Web Flow + Spring MVC + Hibernate或Spring + Hibernate + Web Services。
我们的架构的一个显着特征是模块化。 我们有许多模块,其中一些以数据库中的3到30个表格开始。 大多数模块由业务和Web项目组成。 业务项目持有业务和持久性逻辑,而Web则持有表示逻辑。
在逻辑层面上,有三层:商业,持久性和演示。
依赖关系:
演示取决于业务和持久性。
持久性取决于业务。
业务不依赖于其他层。
大多数业务项目有三种types的接口(注意:不是GUI,它是一个程序化的java接口层)。
- 演示文稿用作客户端的界面
- 当其他模块是模块的客户端时使用的接口。
- 可用于模块pipe理目的的接口。
通常情况下,1扩展为2.这样,很容易将模块的一个实现replace为另一个。 这有助于我们采用不同的客户,更容易整合。 有些客户只会购买某些模块,我们需要集成他们已有的function。 由于接口和实现层是分开的,因此很容易为特定的客户端部署ad-hock模块实现,而不会影响相关的模块。 Spring框架可以很容易地注入不同的实现。
我们的业务层是基于POJO的。 我观察到的一种趋势是这些POJO类似于DTO。 我们患有贫血域模型 。 我不太清楚为什么会发生这种情况,但这可能是由于我们许多模块的问题域的简单性,大部分工作是CRUD,或者是由于开发人员宁愿将逻辑放在其他地方。
这里有一个我已经工作的网页架构:
一个主要的要求是应用程序应该支持手机/其他设备。 应用程序也应该是可扩展的或灵活的,以改变技术select。
演示文稿层:
- JSP / JQuery(客户端MVC)
- 原生Android
- 本机iPhone
-
移动网站(HTML5 / CSS3 /自适应devise)
-
Spring REST控制器(可以更改为JAX-RS)
业务服务层:
Spring @Service(可以更改为无状态EJB)
数据访问层:
Spring @ Repository(可以更改为无状态EJB)
资源层:
Hibernate(JPA)实体(可以更改为任何ORM)
你可以在这里find关于这个架构的书的更多信息。
恕我直言,我们大多数人有一个共同的标准。 至less在后端,我们有一些forms的IOC / DI容器和持久性框架。 我个人使用Guice和Mybatis。 差异在于我们如何实现视图/ UI /表示层。 这里有两个主要的选项(可能会更多)..基于操作(URL映射到控制器)和基于组件。 目前正在使用基于组件的表示层(使用wicket)。 它完美地模拟了我使用组件和事件的桌面环境,而不是URL和控制器。 我目前正在寻找一个为什么我应该迁移到这种URL控制器types的体系结构(这就是我最终在这个页面上)的原因。 为什么宣传RESTful和无状态架构。
简单地回答这个问题:我使用面向组件的框架在Guice IOC容器之上编写了有状态的Web应用程序,并使用Mybatis将数据放入关系数据库中。
有点不同,我会在这里声称更多模块化的Java架构。 我们有:
- Spring WS / Rest / JSP前端
- 用于业务服务逻辑的Spring MVC,包含表示层逻辑以及Spring事务
- 组件服务通信接口,由业务服务通过EJB查找。 EJB设置了自己的能够joinSpring事务的事务边界。
- 组件服务实现,再次Spring组件
- 集成层,用于数据库集成的MyBatis,用于Web服务集成的Spring WS,以及用于其他服务的其他集成技术
- 大型机,数据库,在其他服务器上的其他服务…
除上述之外,我们还有共享库模块,它是所有服务器的通用function提供者。
使用不同的图层可以使我们完全解耦和我们需要的模块化。 我们也能够充分利用Java EE和Spring的强大function。 如果需要的话,没有什么能够阻止我们使用JSF,例如,用于前端。
与OP的示例架构相比,我认为这可以被描述为具有四个主层而不是三个,虽然有一个扭曲。
我一直在使用刚性pipe理模式的项目。 从历史上看,我是坚定的层级的一个巨大的支持者,一切都融入一个整洁的盒子里。 随着我的职业生涯的进展,我发现在很多情况下都是被迫的。 我相信对应用程序devise采取更灵活的思维方式会带来更好的产品。 我的意思是通过创build一组解决当前问题的类。 而不是说“你为此build立了一个经理?”
我正在开发的当前项目是一个Web应用程序,结合了Spring MVC和RestEasy JSON / Ajax调用。 在服务器端embedded我们的控制器是一个合理的基于外观的数据层与JPA / Hibernate的直接数据库访问,一些EJB访问,和一些基于SOAP的Web服务调用。 把所有这些绑在一起是一些自定义的java控制器代码,它决定了如何序列化为JSON并返回给客户端。
我们几乎没有时间尝试创build一个统一的模式,而是select采用Unixdevise理念的“更糟糕更好”的概念。 因为它更好的颜色外线和build立一些明智的,比build立一个坚持一堆严格的devise要求的东西快。
Web应用程序体系结构中的组件包括:
1:浏览器:客户端交互
HTML JavaScript Stylesheet
2:互联网
3:networking服务器
CSS Image Pages(Java render )
4:应用程序服务器
App Webapp (Java interaction) Others WebApps
5:数据库服务器
Oracle, SQL, MySQL
6:数据