分类目录归档:编程技术

涵盖PHP、Java、.Net开发技术有关的内容,或原创分享,或转载学习。

Java微服务的模块划分

近段时间在推进公司内Java微服务的框架升级,有机会直面一线业务的很多服务,在这个过程中也发现一些有趣的事情:不同时间段,不同团队,大家对于Java服务的模块划分、模块或者Jar包发布、模块包的依赖管理做法都有所不同,今天正好借这篇文章,和大家聊一下。

从再熟悉不过的模块结构划分开始

在盘点业务服务时发现,大多数项目都采取了如下或者与之类似的项目模块结构:

  • business-api —— 对外发布的API接口,例如Dubbo协议的Service
  • business-dao —— 数据访问对象,多数项目使用了MyBatis,这里是Mapper的聚集地
  • business-model —— 模型,包括各类的实体、DTO等
  • business-service —— 业务逻辑层,包括各类Service、接口、实现等
  • business-web —— Web请求处理层,包括Controller等

它的命名规则可以概括为<服务名>-<模块名>,除了上面列出的模块外,常见的可能还有像business-core、business-common等。这种模块划分模式很常见,在大量的Java服务项目中得以采用。模块划分的依据也就是应用的分层结构,例如阿里巴巴的Java开发手册中推荐的应用分层模式为:

来自阿里巴巴Java开发手册,建议的应用分层

我们可以把这种类型的项目模块划分看做对这种分层模式的一种落地,所以要探讨模块划分的问题,我们需要先了解一下应用分层模式的由来。

继续阅读

基于Twitter的Snowflake算法实现发号器

在微服务架构的系统中,ID号的生成是一个需要考虑的问题。通常单体系统会依赖RDB的自增字段(例如MySQL)或者序列(例如PostgreSQL等)来产生业务序号。在微服务架构的系统中也使用类似的方式时就会出现一些问题。

在单体系统中,我们可能会使用自增字段,或者序列,它们通常依赖于关系型数据库插入动作时产生的ID。不过由于ID是在持久化到数据库时才产生,所以我们无法提前获取一个ID号。对于单体系统而言并没有什么问题,但当存在多个系统协作时,我们可能希望提前生成业务的ID号,以保证业务可以以幂等的方式进行操作。为了解决这个问题,ID生成可以先独立出单独的模块,每次产生一个新的ID号供业务方使用。

不过利用RDB的序列(MySQL可以模拟一个序列)来进行发号,通常存在性能瓶颈。因为业务操作必须先在RDB操作后,才能取得新的ID号。一旦RDB是单点系统,那么所有业务的可用性都会受到影响。另外连续的ID号可能会暴露业务的信息,通过ID号可以间接地刺探到业务的规模,也更容易受到攻击,一旦存在权限验证不严的系统,攻击者可以轻而易举的枚举全部的信息访问。

UUID是一种专门设计用来在分布式系统中生成ID的工具。它可以产生一个128bit的ID号。目前常见的版本是v1和v4,其中v1版本使用时间戳、MAC地址、随机数来生成一个ID号,v4版本使用随机数来产生ID号。但是UUID通常情况下过于冗长,存储为一个32+4个字符串,作为业务ID使用并不方便,另外UUID依然存在冲突的可能性,只不过这种可能系非常低。

使用UUID用做分布式系统的ID生成器是一种选择,但是更多时候我们希望ID号可以:

  • 生成高效,可分布式并行发号
  • 大致时间顺序(对于数据分片、排序友好)
  • 稀疏不连续
  • 可以使用64bit整型存储
  • 可预见的时间范围内不重复

Twitter开源了他们的ID生成器,被称作snowflake,项目地址在https://github.com/twitter/snowflake。不过目前Twitter已经完全重写了他们的发号器,因此这个项目现在处于关闭状态,参考源代码只能查看2010年的初始tag,目前也不再维护这个项目了。

继续阅读

责任链模式:一个PHP实现的过滤器

上次讲到责任链模式的时候,我顺手实现了一个过滤器,分享给新人。SimpleMVC框架中,过滤器链是整个HTTP请求处理的核心组件。

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

fitlers

Talk is cheap, show me the code.

继续阅读

一道关于PHP类型转换的面试题

最近在为公司面试新人,经常会问到的一道题目就是PHP类型转换的值,例如:

var_dump((int)true);
var_dump((string)true);
var_dump((string)false);
var_dump((bool)"1");
var_dump((bool)"0");
var_dump((bool)"");
var_dump((bool)"false");

我印象中最早见到这道题目是在英极的PHP高级开发工程师岗位的笔试题里面,看似很基础,但是依然可以难住不少PHPer。先来看一下运行结果:

int(1)
string(1) "1"
string(0) ""
bool(true)
bool(false)
bool(false)
bool(true)

对于大多数人来说,第1、2、4行通常是没有问题的。但是为什么false转换为字符串是空字符串呢?在处理请求值时,通常会传一个字符串类型的false,但是“false”(字符串)并非false(布尔),这有点令人疑惑了。

为什么会这样呢? 继续阅读

PHP使用数据库的并发问题

在并行系统中并发问题永远不可忽视。尽管PHP语言原生没有提供多线程机制,那并不意味着所有的操作都是线程安全的。尤其是在操作诸如订单、支付等业务系统中,更需要注意操作数据库的并发问题。

接下来我通过一个案例分析一下PHP操作数据库时并发问题的处理问题。

首先,我们有这样一张数据表:

mysql> select * from counter;
+----+-----+
| id | num |
+----+-----+
|  1 |   0 |
+----+-----+
1 row in set (0.00 sec)

继续阅读

进阶PHP需要注意的一些点

最近写了一段时间PHP,发现了不少以前没有注意到或者意识到的事情,写一篇记录分享一下。PHP进阶一定要注意这些事情。

用好PECL

PECL(The PHP Extension Community Library),PHP官方提供的PHP扩展库。这个主要可以解决社区和第三方提供的PHP扩展的安装问题。早些年看张宴老师的PHP编译部署的文档,生产环境的PHP扩展安装从那时起都是从网站上下载,然后自己编译安装。后来PHP版本升级后,原来文档里面提供的扩展包已经不能匹配新版PHP环境了。其实PHP一直都有PECL这个工具用来管理第三方扩展,使用起来非常方便。

在Linux/Unix/MacOS上,使用PECL是一件非常方便的事情。如果你的PHP环境是自己编译的,在PHP的安装目录的bin下会有pecl这个文件,把它软链到/usr/bin下面你就可以随时使用pecl了。以下给出两种软链它的方案,Linux发行版推荐使用alternatives工具。

我的PHP安装在:/usr/local/php-5.5.10

继续阅读

关于EnitiyFramework的ObjectConext生命周期

最近在一个项目里用了EntityFramework作为持久层。发现在Web系统中使用EF框架还是有一些东西需要注意的。有一点就是ObjectContext的生命周期。

在见到的多数EF框架的实例代码中,很多人喜欢使用using语句方式创建ObjectContext,最初我的代码也是这样书写的,后来发现其实有很多不便。然后仔细研究了一下到底应该怎么管理ObjectConext的生命周期。这儿常见的ObjectContext生命周期管理方式有四种:

  • 每个原子操作分配一个ObjectContext
  • 全局共用一个ObjectContext
  • 每个线程创建一个ObjectContext
  • 每个业务对象分配一个ObjectConext

原子操作分配ObjectConext,就是常见的using方式,一系列操作创建一个对象,用后即销毁。代码常常是这种:

using(var context = new DbEntities())
{
    // some operations
    ....
}

我在DAO中使用了这种写法,但是并不方便。因为DAO层只应该负责数据的读写,那么一次数据操作上下文对象结束了,但是业务中,通常要多长存取,实体对象要再次持久化,就比较麻烦了(一个实体是关联到一个ObjectContext对象的,不能关联多个,关联不一致也不能被保存)。最后被迫把复杂的逻辑推向了DAO,这影响了架构的稳定性。在WebService类型的应用中使用这种方式,还是很科学的。因为WebService本身就是无状态的,原子操作内使用一个ObjectContext对象是非常科学的。

全局共用一个ObjectContext,即系统启动的时候,创建一个ObjectContext对象保存到静态变量里面。这种方式适合于桌面应用,多线程应用中可能会出现并发问题,或者效率问题。

为每个线程创建一个ObjectContext,这种做法比较适合于Web应用。ASP.NET的Web应用里面每个请求都是短暂的,在一个请求内使用一个ObjectContext,可以很方便的管理上下文。实现的思路很简单,将ObjectContext添加到HttpContext中,在RequestEnd事件时销毁。关于这个的实现,可以参考这篇文章:

《自定义Unity对象生命周期管理集成ADO.NET Entity Framework》

http://www.cnblogs.com/shanyou/archive/2008/08/24/1275059.html

这篇文章里面使用Unity这个简单的DI容器。

每个请求一个ObjectContext对象的方式,更像是Hibernate的Session对象的使用方式。在和Spring整合后,利用Filter实现将Session的生命周期延长至视图。

对每个业务对象分配一个ObjectContext的方式,就是针对每个实体进行上下文对象的分配。这种方式还没有真正使用过,不好做评论,只是看到一些技术文章里面有提到。

微信公众平台接入的安全性

最近微信公众平台非常红火,基于公众平台的接入应用也越来越多。不过在处理接入入口的安全问题上,可能不是那么的严谨。现在我们来讨论下如何保证微信公众平台接入的安全性。

根据微信官方提供的消息接口指南,微信公众平台分为接入和使用两步。接入程序官方提供了一个简单的例子,我们来回顾一下接入认证的方式:

继续阅读

使用Entity Framework访问MySQL数据库

简介

Entity Framework (EF,ADO.NET Entity Framework)是微软官方提供的.NET平台的ORM框架。相比于LINQ TO SQL,EF框架具有很明显的优势:

  • EF框架支持多种数据库,而不仅仅局限于微软的SQL Server,MySQL,Oracle都有良好的支持。
  • 支持存储过程。
  • 强大的可视化模型设计工具,与Visual Studio深度整合。
  • 与.NET平台的其他技术整合良好。

继续阅读