Re:从零开始的Spring Security OAuth2(一)

前言

今天来聊聊一个接口对接的场景,A厂家有一套HTTP接口需要提供给B厂家使用,由于是外网环境,所以需要有一套安全机制保障,这个时候oauth2就可以作为一个方案。

关于oauth2,其实是一个规范,本文重点讲解spring对他进行的实现,如果你还不清楚授权服务器,资源服务器,认证授权等基础概念,可以移步理解OAuth 2.0 - 阮一峰,这是一篇对于oauth2很好的科普文章。

需要对spring security有一定的配置使用经验,用户认证这一块,spring security oauth2建立在spring security的基础之上。第一篇文章主要是讲解使用springboot搭建一个简易的授权,资源服务器,在文末会给出具体代码的github地址。后续文章会进行spring security oauth2的相关源码分析。java中的安全框架如shrio,已经有跟我学shiro - 开涛,非常成体系地,深入浅出地讲解了apache的这个开源安全框架,但是spring security包括oauth2一直没有成体系的文章,学习它们大多依赖于较少的官方文档,理解一下基本的使用配置;通过零散的博客,了解一下他人的使用经验;打断点,分析内部的工作流程;看源码中的接口设计,以及注释,了解设计者的用意。spring的各个框架都运用了很多的设计模式,在学习源码的过程中,也大概了解了一些套路。spring也在必要的地方添加了适当的注释,避免了源码阅读者对于一些细节设计的理解产生偏差,让我更加感叹,spring不仅仅是一个工具框架,更像是一个艺术品。

查看更多

分享到

对于Spring Cloud Feign入门示例的一点思考

Spring Cloud Feign

Spring Cloud Feign是一套基于Netflix Feign实现的声明式服务调用客户端。它使得编写Web服务客户端变得更加简单。我们只需要通过创建接口并用注解来配置它既可完成对Web服务接口的绑定。它具备可插拔的注解支持,包括Feign注解、JAX-RS注解。它也支持可插拔的编码器和解码器。Spring Cloud Feign还扩展了对Spring MVC注解的支持,同时还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。

分布式应用早在十几年前就开始出现,各自的应用运行在各自的tomcat,jboss一类的容器中,他们之间的相互调用变成了一种远程调用,而实现远程调用的方式很多。按照协议划分,可以有RPC,Webservice,http。不同的框架也对他们有了各自的实现,如dubbo(x),motan就都是RPC框架,本文所要讲解的Feign便可以理解为一种http框架,用于分布式服务之间通过Http进行接口交互。说他是框架,有点过了,可以理解为一个http工具,只不过在spring cloud全家桶的体系中,它比httpclient,okhttp,retrofit这些http工具都要强大的多。

入门

先用一个简单的例子,看看如何在项目中使用Feign。示例项目使用maven多module构建,采用springcloud的Dalston.SR1版本

查看更多

分享到

Re:从零开始的领域驱动设计

前言

领域驱动的火爆程度不用我赘述,但是即便其如此得耳熟能详,但大多数人对其的认识,还只是停留在知道它的缩写是DDD,知道它是一种软件思想,或者知道它和微服务有千丝万缕的关系。Eric Evans对DDD的诠释是那么地惜字如金,而我所认识的领域驱动设计的专家又都是行业中的资深前辈,他们擅长于对软件设计进行高屋建瓴的论述,如果没有丰富的互联网从业经验,是不能从他们的分享中获取太多的营养的,可以用曲高和寡来形容。1000个互联网从业者,100个懂微服务,10个人懂领域驱动设计。

可能有很多和我一样的读者,在得知DDD如此火爆之后,尝试去读了开山之作《领域驱动设计——软件核心复杂性应对之道》,翻看了几张之后,晦涩的语句,不明所以的专业术语,加上翻译导致的语句流畅性,可以说观看体验并不是很好,特别是对于开发经验不是很多的读者。我总结了一下,为何这本书难以理解:

  1. 没有阅读软件设计丛书的习惯,更多人偏向于阅读偏应用层面的书籍,“talk is cheap,show me the code”往往更符合大多数人的习惯。
    2.没有太多的开发经验支撑。没有踩过坑,就不会意识到设计的重要性,无法产生共情。
    3.年代有些久远,这本书写于2004年,书中很多软件设计的反例,在当时是非常流行的,但是在现在已经基本绝迹了。大师之所以为大师,是因为其能跨越时代的限制,预见未来的问题,这也是为什么DDD在十几年前就被提出,却在微服务逐渐流行的现阶段才被大家重视。

诚然如标题所示,本文是领域驱动设计的一个入门文章,或者更多的是一个个人理解的笔记,笔者也正在学习DDD的路上,可能会有很多的疏漏。如有理解有偏颇的地方,还望各位指摘。

查看更多

分享到

spring中的懒加载与事务--排坑记录

案例描述

本文主要描述了开发中常见的几个与spring懒加载和事务相关的案例,描述常见的使用场景,以及如何规避他们,给出具体的代码。

  1. 在新的线程中,访问某个持久化对象的懒加载属性。
  2. 在quartz定时任务中,访问某个持久化对象的懒加载属性。
  3. 在dubbo,motan一类rpc框架中,远程调用时服务端session关闭的问题。

上面三个案例,其实核心都是一个问题,就是牵扯到spring对事务的管理,而懒加载这个技术,只是比较容易体现出事务出错的一个实践,主要用它来引发问题,进而对问题进行思考。

查看更多

分享到

使用zipkin做分布式链路监控

介绍

快速入门

  • 安装方式一:使用zipkin官方提供的jar启动服务
    zipkin官方提供了一个现成的使用springboot写的zipkin服务端,客户端的链路监控报告可以通过多种方式(下文会讲解具体的方式)向服务端发送报告。

    配置详解
    存储方式
    查看源码可知其有4种持久化方式,本文选择使用最熟悉的mysql持久化链路调用信息。

首先建立数据库:
默认情况下 zipkin 运行时数据保存在内存中,重启数据会丢失
数据库脚本下载

查看与mysql storage相关的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
@ConfigurationProperties("zipkin.storage.mysql")
public class ZipkinMySQLStorageProperties implements Serializable { // for Spark jobs
private static final long serialVersionUID = 0L;

private String host = "localhost";
private int port = 3306;
private String username;
private String password;
private String db = "zipkin";
private int maxActive = 10;
private boolean useSsl;
...
}

所以,我们使用mysql作为持久化策略,启动服务端的脚本也就有了

1
java -server -jar zipkin-server-1.26.0-exec.jar --zipkin.storage.type=mysql --zipkin.storage.mysql.host=localhost --zipkin.storage.mysql.port=3306 --zipkin.storage.mysql.username=root --zipkin.storage.mysql.password=root --zipkin.storage.mysql.db=zipkin

  • 安装方式二
    springcloud官方按照传输方式分成了三种启动服务端的方式:Sleuth with Zipkin via HTTP,Sleuth with Zipkin via Spring Cloud Stream,Spring Cloud Sleuth Stream Zipkin Collector。只需要添加相应的依赖,之后配置相应的注解,如@EnableZipkinStreamServer即可。具体配置参考Spring Cloud官方文档

项目中,我们使用第一种作为服务端的启动方式,使用mysql作为持久化方案

查看更多

分享到

JAVA程序员分级,你属于哪一种?

  • 初级—初

    掌握java基础,熟悉常用类库。理解java web中的servlet,jsp,并了解常用的框架对java web的封装原理,能够借助框架完成增删改查功能。理解数据库在web开发中的地位。

  • 初级—中

    理解java中较为高级的特性,如反射,动态代理,JVM,内存模型,多线程等等。熟练使用框架,对框架中遇到的bug,能够借助日志和搜索引擎分析出问题的原因。在团队中,能够独立完成普通后台业务功能的开发。了解数据库的高级特性,如索引,存储引擎等等。

  • 初级—高

    理解java分布式架构,微服务架构,了解其与集中式架构的区别,并能保证分布式代码质量。熟练使用各个中间件如redis,mq,zookeeper等等,并了解其工作原理和使用场景。能够在中级或高级程序员的带领之下,完成非核心功能的研发。能够关注开源,并且具有阅读源码的能力。

  • 中级

    具备一定的项目开发经验(3年之上一线互联网产品研发经验),拥有线上bug的处理能力,JVM调优能力,以及完成核心业务功能的开发。并且带领团队的新人,能够按能力分配任务。

  • 高级

    团队的核心人物,把控整个项目的质量,包括代码漏洞和规范问题。具有5年以上项目开发经验,2年以上架构搭建的经验,能够根据业务选择不同的架构类型;根据团队组成,分配不同的任务。具有将自己的知识分享出去的能力,带领初级程序员走向中级,中级程序员走向高级的能力。

分享到

drools用户指南----Cross Products

Cross Products

之前提到“Cross Products”一词,其实就是一个join操作(译者注:可以理解为笛卡尔积)。想象一下,火灾报警示例的数据与以下规则结合使用,其中没有字段约束:

1
2
3
4
5
6
7
rule "Show Sprinklers" when
$room : Room()
$sprinkler : Sprinkler()
then
System.out.println( "room:" + $room.getName() +
" sprinkler:" + $sprinkler.getRoom().getName() );
end

在SQL术语中,这就像是执行了select * from Room, Sprinkler,Sprinkler 表中的每一行将与Room表中的每一行相连接,从而产生以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
room:office sprinkler:office
room:office sprinkler:kitchen
room:office sprinkler:livingroom
room:office sprinkler:bedroom
room:kitchen sprinkler:office
room:kitchen sprinkler:kitchen
room:kitchen sprinkler:livingroom
room:kitchen sprinkler:bedroom
room:livingroom sprinkler:office
room:livingroom sprinkler:kitchen
room:livingroom sprinkler:livingroom
room:livingroom sprinkler:bedroom
room:bedroom sprinkler:office
room:bedroom sprinkler:kitchen
room:bedroom sprinkler:livingroom
room:bedroom sprinkler:bedroom

这些连接结果显然会变得巨大,它们必然包含冗余数据。 cross products的大小通常是新规则引擎产品性能问题的根源。 从这可以看出,我们希望约束cross products,这便是用可变约束(the variable constraint)完成的。

1
2
3
4
5
6
7
8
rule
when
$room : Room()
$sprinkler : Sprinkler( room == $room )
then
System.out.println( "room:" + $room.getName() +
" sprinkler:" + $sprinkler.getRoom().getName() );
end

这就使得筛选结果只有寥寥几行, 这就为每一个Room筛选出了正确的Sprinkler. 在sql中(实际上是HQL) 这样的查询约等于select * from Room, Sprinkler where Room == Sprinkler.room.

分享到

drools用户指南----Methods vs Rules

Methods vs Rules

人们经常混淆方法和规则,初学者经常会问:“我如何理解规则的含义?“ 在最后一节之后,你会对规则的使用得心应手,答案也变得显而易见的,但在这之前,先让我们总结一下方法判断和规则的差异。

1
2
3
4
5
public void helloWorld(Person person) {
if ( person.getName().equals( "Chuck" ) ) {
System.out.println( "Hello Chuck" );
}
}
  1. 方法是被直接调用的
  2. 需要传递具体的实例
  3. 一个调用导致一次执行(One call results in a single execution)。
1
2
3
4
5
rule "Hello World" when
Person( name == "Chuck" )
then
System.out.println( "Hello Chuck" );
end
  1. 只要将其插入引擎,就可以通过匹配任何数据执行规则。
  2. 规则永远无法被直接调用,而只能触发
  3. 无法将特定的实例传递给规则
  4. 根据匹配,一个规则可能会触发一次或多次,或根本不被触发。
分享到

drools用户指南----stateless session(无状态会话)的使用

stateless session 无状态会话

Drools规则引擎中有如此多的用例和诸多功能,它变得令人难以置信。不过不用担心,复杂性是分层的,你可以用简单的用例来逐步了解drools。

无状态会话,不使用推理,形成最简单的用例。无状态会话可以被称为函数传递一些数据,然后再接收一些结果。无状态会话的一些常见用例有以下但不限于:

  1. 验证
    这个人有资格获得抵押吗?
  2. 计算
    计算抵押保费。
  3. 路由和过滤
    将传入的邮件(如电子邮件)过滤到文件夹中。
    将传入的邮件发送到目的地。

所以让我们从使用驾驶执照应用程序的一个非常简单的例子开始吧。

1
2
3
4
5
6
public class Applicant {
private String name;
private int age;
private boolean valid;
// getter and setter methods here
}

现在我们有了我们的数据模型,我们可以写出我们的第一个规则。我们假设应用程序使用规则来拒绝不符合规则的申请。由于这是一个简单的验证用例,我们将添加一条规则来取消任何18岁以下的申请人的资格。

1
2
3
4
5
6
7
8
package com.company.license

rule "Is of valid age"
when
$a : Applicant( age < 18 )
then
$a.setValid( false );
end

查看更多

分享到

drools用户指南----stateful session(有状态会话)的使用

stateful session 有状态会话

有状态会话长期存在,并允许随着时间的推移进行迭代更改。 有状态会话的一些常见用例包括但不限于:

  1. 监测
    半自动买入股票市场监控与分析。
  2. 诊断
    故障查找,医疗诊断
  3. 物流
    包裹跟踪和送货配置
  4. 合规
    验证市场交易的合法性。

与无状态会话相反,必须先调用dispose()方法,以确保没有内存泄漏,因为KieBase包含创建状态知识会话时的引用。 由于状态知识会话是最常用的会话类型,所以它只是在KIE API中命名为KieSession。 KieSession还支持BatchExecutor接口,如StatelessKieSession,唯一的区别是FireAllRules命令在有状态会话结束时不被自动调用。

我们举例说明了用于提高火灾报警器的监控用例。 只使用四个类,我们假设Room代表房子里的房间,每个Room都有一个喷头Sprinkler。 如果在房间里发生火灾,我们用一个Fire实例来表示,用Alarm代表警报 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Room {
private String name
// getter and setter methods here
}

public class Sprinkler {
private Room room;
private boolean on;
// getter and setter methods here
}

public class Fire {
private Room room;
// getter and setter methods here
}

public class Alarm {
}

在上一节无状态会话中介绍了插入和匹配数据的概念。 这个例子假设每个对象类型的都是单个实例被插入的,因此只使用了字面约束。 然而,房子有许多房间,因此rules必须表达实体类之间的关系,例如在某个房间内的喷洒器。 这最好通过使用绑定变量作为模式中的约束来完成。 这种“加入”过程产生了所谓的“cross products”,这在下一节中将会介绍。

查看更多

分享到