简答
mock方法和spy方法都可以对对象
进行mock。但是前者是接管了对象的全部方法,而后者只是将有桩实现(stubbing)的调用进行mock,其余方法仍然是实际调用。
记录一些日常接触到的专业知识
@Mock
和@InjectMocks
的区别Difference Between @Mock
and @InjectMocks
@Mock
创建一个mock,@InjectMocks
创建一个实例并且将注入由@Mock
或者@Spy
注解生成的mock。注意,需要通过
@Runwith(MockitoJUnitRunner.class)
或者@Mockito.initMocks(this)
来初始化这些mocks并注入。
Apache Commons Chain是什么
Apache Commons Chain是对责任链设计模式的改造封装,让使用者更加方便的使用。
责任链模式
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
关键点:
Commons Chain实现了Chain of Responsebility和Command模式,其中的Catalog + 配置文件的方式使得调用方和Command的实现方的耦合度大大的降低,提高了灵活性。
在下面三种情况下,命令链将结束:
execute
方法返回true当有命令抛出错误时,链就会非正常结束。在Commons Chain中,如果有命令抛出错误,链的执行就会中断,将异常抛出给链的调用者。
许多应用需要对在命令之外定义的错误做明确的处理。Commons Chain提供了Filter接口来满足这个要求。
Filter继承了Command,添加了一个名为postprocess的方法。
只要Filter的execute方法被调用,不论链的执行过程中是否抛出错误,Commons Chain都将保证Filter的postprocess方法被调用。
通过@Order
注解或者实现Ordered
接口,可以实现Bean之间的排序顺序。
如下:1
2
3
4
5
6
7
8
9
10
11
12@Component
public class Cars {
@Autowired
List<Car> cars;
public void printNames() {
for(Car car : cars) {
System.out.println(car.getName());
}
}
}
当Car
的子类通过@Order
注解或者实现Ordered
接口,@Autowired
的cars在注入时,会将value
值小的优先加入,实现子类bean
的自动排序。
使用Objects.equal
可以避免NPE。如下所示:1
2
3
4Objects.equal("a", "a"); // returns true
Objects.equal(null, "a"); // returns false
Objects.equal("a", null); // returns false
Objects.equal(null, null); // returns true
在JDK 7中有提供等价方法
在实现Comparable接口时,通常的做法是1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Person implements Comparable<Person> {
private String lastName;
private String firstName;
private int zipCode;
public int compareTo(Person other) {
int cmp = lastName.compareTo(other.lastName);
if (cmp != 0) {
return cmp;
}
cmp = firstName.compareTo(other.firstName);
if (cmp != 0) {
return cmp;
}
return Integer.compare(zipCode, other.zipCode);
}
}
有了ComparsionChain
之后,可以这样实现1
2
3
4
5
6
7public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(this.aString, that.aString)
.compare(this.anInt, that.anInt)
.compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
.result();
}
排序
Ordering支持链式调用。例如,我们想要以下类的一个包含null值的sortedBy
字段的比较器。1
2
3
4class Foo {
@Nullable String sortedBy;
int notSortedBy;
}
可以这么写:1
2
3
4
5Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(new Function<Foo, String>() {
public String apply(Foo foo) {
return foo.sortedBy;
}
});
该Ordering需要从右往左读,先读取sortedBy的值,再null置顶,再按照String
类型的自然顺序排序。
用于过滤异常或者得到异常链等
相同的元素可以出现多次
ArrayList
Map<E, Integer>
一般,我们为了保持value
到key
的映射,会如下设置:1
2
3
4
5
6
7Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();
nameToId.put("Bob", 42);
idToName.put(42, "Bob");
// what happens if "Bob" or 42 are already present?
// weird bugs can arise if we forget to keep these in sync...
BiMap<K, V>
是一个保持以下特性的Map<K, V>
:
inverse()
来获取BiMap<K, V>
的倒置视图value
是唯一的支持行、列,如:1
2
3
4
5
6
7Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);
weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5
描述一个不相连的,非空的range的集合。连接的range之间会合并,空的range会被忽略。
1 | RangeSet<Integer> rangeSet = TreeRangeSet.create(); |
Maps:
Maps.uniqueIndex(Iterable, Function
生成唯一键可以索引的Map。
1 | ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings, new Function<String, Integer> () { |
customTable
,transpose
Guava提供两个基本的“函数式”接口:
Function<A, B>
Predicate<T>
TO BE CONT.
继承AbstractProcessor这个类,基本的框架大体如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.mythsman.test;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import java.util.Set;
@SupportedAnnotationTypes("com.mythsman.test.Getter")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class GetterProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return true;
}
}
需要着重实现两个方法:
1 | private Messager messager; |
1 | @Override |
接下来再实现makeGetterMethodDecl方法:1
2
3
4
5
6
7
8
9
10private JCTree.JCMethodDecl makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
statements.append(treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.getName())));
JCTree.JCBlock body = treeMaker.Block(0, statements.toList());
return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), getNewMethodName(jcVariableDecl.getName()), jcVariableDecl.vartype, List.nil(), List.nil(), List.nil(), body, null);
}
private Name getNewMethodName(Name name) {
String s = name.toString();
return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));
}
2018-08-08
数据库:保存有组织的数据的容器
表:某种特定类型数据的结构化清单
模式(schema):关于数据库和表的布局及特性的信息
主键(PK):一列(或一组列),其值能够唯一区分表中的每个行。主键列不允许NULL值
应该总是定义主键 虽然并不总是都需要主键
MySQL的默认端口:3306
USE #{database} 选择一个数据库
SHOW DATABASES 显示可用的数据库列表
SHOW TABLES 显示数据库内的可用表
SHOW COLUMNS FROM #{table} 返回表的详细信息,DESCRIBE #{table}是该命令的一种快捷方式
1 | SELECT prod_name |
1 | SELECT DISTINCT vend_id |
不能部分使用DISTINCT
开放授权的例子:泊车钥匙,让渡部分权利(启动发动机,行驶一段距离)给服务生。
用 用户名/密码 授权的缺点:
开放授权(Open Authorization):帮助用户将资源授权给第三方,支持细粒度的权限控制
开放授权的主流方法有:OAuth协议和IAM服务,后者主要用户离线授权或者预先授权。
OAuth协议的特点在于在线授权(现场授权)。
如图1所示,协议的基本流程如下:
(1) Client请求RO的授权,请求中一般包含:要访问的资源路径,操作类型,Client的身份等信息。
(2) RO批准授权,并将“授权证据”发送给Client。至于RO如何批准,这个是协议之外的事情。典型的做法是,AS提供授权审批界面,让RO显式批准。这个可以参考下一节实例化分析中的描述。
(3) Client向AS请求“访问令牌(Access Token)”。此时,Client需向AS提供RO的“授权证据”,以及Client自己身份的凭证。
(4) AS验证通过后,向Client返回“访问令牌”。访问令牌也有多种类型,若为bearer类型,那么谁持有访问令牌,谁就能访问资源。
(5) Client携带“访问令牌”访问RS上的资源。在令牌的有效期内,Client可以多次携带令牌去访问资源。
(6) RS验证令牌的有效性,比如是否伪造、是否越权、是否过期,验证通过后,才能提供服务。
4.1 为何引入authorization_code?
(1) 浏览器的redirect_uri是一个不安全信道,此方式不适合于传递敏感数据(如access_token)。因为uri可能通过HTTP referrer被传递给其它恶意站点,也可能存在于浏览器cacher或log文件中,这就给攻击者盗取access_token带来了很多机会。另外,此协议也不应该假设RO用户代理的行为是可信赖的,因为RO的浏览器可能早已被攻击者植入了跨站脚本用来监听access_token。因此,access_token通过RO的用户代理传递给Client,会显著扩大access_token被泄露的风险。 但authorization_code可以通过redirect_uri方式来传递,是因为authorization_code并不像access_token一样敏感。即使authorization_code被泄露,攻击者也无法直接拿到access_token,因为拿authorization_code去交换access_token是需要验证Client的真实身份。也就是说,除了Client之外,其他人拿authorization_code是没有用的。 此外,access_token应该只颁发给Client使用,其他任何主体(包括RO)都不应该获取access_token。协议的设计应能保证Client是唯一有能力获取access_token的主体。引入authorization_code之后,便可以保证Client是access_token的唯一持有人。当然,Client也是唯一的有义务需要保护access_token不被泄露。
(2) 引入authorization_code还会带来如下的好处。由于协议需要验证Client的身份,如果不引入authorization_code,这个Client的身份认证只能通过第1步的redirect_uri来传递。同样由于redirect_uri是一个不安全信道,这就额外要求Client必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。引入authorization_code之后,AS可以直接对Client进行身份认证(见步骤4和5),而且可以支持任意的Client认证方式(比如,简单地直接将Client端密钥发送给AS)。
Q1: 静默授权(snsapi_base)有什么作用?
网页授权(snsapi_userinfo)需要用户点击同意,允许后,可以获取用户的基本信息。已关注的用户进入网页授权页,也是静默的,无需用户同意。静默授权(snsapi_base)只能拿到唯一标识openId。从现状看,静默授权的作用,也就是用来判断用户的唯一性,查看用户是否关注了该公众号
事件的来源是SpringApplication,事件发生时,所有的初始化步骤都已经完成。
1 | @Component |
1 | @Component |