predicate的大致设计思路。
从uml类图看初始接口RoutePredicateFactory。PredicateFactory顾名思义Predicate工厂,这是一个函数式接口,函数式方法就是工厂方法apply(Config config).
Predicate<ServerWebExchange> apply(C config);返回一个Predicate实例。
抽象方法增加了对configConfigurable的抽象类,顾名思义这厮一个可配置配置化支持接口。用于获取我们在yml配置时候注入的配置对象。
public abstract class AbstractRoutePredicateFactory<C> extends AbstractConfigurable<C> implements RoutePredicateFactory<C> {
public AbstractRoutePredicateFactory(Class<C> configClass) { super(configClass); }
}
下面是AfterRoutePredicateFactory的源码,主要就是实现apply方法,和声明的静态内部类Config类.很显然只需要获取一个配置时间。所以Config的参数也就只有时间。
public class AfterRoutePredicateFactory
extends AbstractRoutePredicateFactory<AfterRoutePredicateFactory.Config> {
/**
* DateTime key.
*/
public static final String DATETIME_KEY = "datetime";
public AfterRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList(DATETIME_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
ZonedDateTime datetime = config.getDatetime();
return exchange -> {
final ZonedDateTime now = ZonedDateTime.now();
return now.isAfter(datetime);
};
}
public static class Config {
@NotNull
private ZonedDateTime datetime;
public ZonedDateTime getDatetime() {
return datetime;
}
public void setDatetime(ZonedDateTime datetime) {
this.datetime = datetime;
}
}
}
把apply方法单独拎出来,这是一个lambda的写法,这里声明了一个Predicate<ServerWebExchange>类型的匿名内部类。Predicate也是一个函数式接口,它的函数式方法test,所以lambda表达式{}部分就是test的实现。而exchange就是test的参数。
@Override
public Predicate<ServerWebExchange> apply(Config config) {
ZonedDateTime datetime = config.getDatetime();
return exchange -> {
final ZonedDateTime now = ZonedDateTime.now();
return now.isAfter(datetime);
};
}
Predicate接口源代码,一个函数式泛型接口。参数化类型T.也就是上面的ServerWebExchange.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
源码的内部设计流程呢是。从工厂类PredicateFactory开始,在这里定义配置类Config,我们调用工厂方方法aplay(),传递进去不同的配置文件生成一个个Predicate<ServerWebExchange>匿名内部类,同时实现了test方法(声明Predicate的内部类必须实现它的非默认方法)。Predicate实例至此被加载,在被调用的时候传入ServerWebExchange实例。整个流程就是这么回事了。
自定义PredicateFactory,需要注意的就是config定义,config参数注入(shortcutFieldOrder这个方法排序注入)。然后就是根据需求编写test了。
@Component
public class AgeRoutePredicateFactory
extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
/**
* Name key.
*/
public static final String AGE_KEY = "age";
public AgeRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(AGE_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
//奶奶的这个exchange是被传进来的
return exchange -> {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
String age = queryParams.getFirst("age");
if (!StringUtils.isEmpty(age) && age.matches("[0-9]+")) {
int iAge = Integer.parseInt(age);
if (iAge < config.getAge()) {
return true;
}
}
return false;
};
}
@Validated
public static class Config {
@NotNull
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}