前言
本系列的目的是明明白白、彻彻底底的搞定日期/时间处理的几乎所有case。上篇文章铺设所有涉及到的概念解释,例如GMT、UTC、夏令时、时间戳等等,若你还没看过,不仅强烈建议而是强制建议你前往用花5分钟看一下,因为日期时间处理较为特殊,实战必须基于对概念的了解,否则很可能依旧雾里看花。
说明:日期/时间的处理是日常开发非常常见的老大难,究其原因就是对日期时间的相关概念、应用场景不熟悉,所以不要忽视它
本文落地实操,二者相辅相成,缺一不可。本文内容较多,文字较长,预计超2w字,旨在全面的彻底帮你搞定Java对日期时间的处理,建议你可收藏,作为参考书留以备用。
本文提纲
public interface HelloService {
@GET(“/hello-obj”)
Call hello(@Query(“name”) String name);
}
- 在业务要做远程调用的时候,用Autowired注解修饰HelloService接口,即可调用HelloService.hello方法,至于接口对应的实例来自哪里,开发者不必关注:
@RestController
public class RemoteHello {
@Autowired(required = false)
HelloService helloService;
@GetMapping(“/remote-obj”)
public HelloResponse hello(@RequestParam(“name”) String name) throws IOException {
return helloService.hello(name).execute().body();
}
}
- 以上就是咱们开发业务代码时使用spring-cloud-square的关键操作,接下来就从源码角度来分析这些操作到底发挥了什么作用
[](()源码分析(类定义注册阶段)
- 回忆一下咱们写的OkHttpClientConfig.java,里面使用了注解EnableRetrofitClients,这就是本次阅读代码的入口:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ RetrofitConfiguration.class, RetrofitClientsRegistrar.class })
public @interface EnableRetrofitClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
-
从上述代码可见RetrofitConfiguration和RetrofitClientsRegistrar都会比实例化,RetrofitConfiguration过于简单就不看了,重点关注RetrofitClientsRegistrar,先来看它的类图,搞清楚继承和实现
-
如下图所示,RetrofitClientsRegistrar集成自AbstractRetrofitClientsRegistrar,而AbstractRetrofitClientsRegistrar又集成自ImportBeanDefinitionRegistrar
-
所以,RetrofitClientsRegistrar被实例化的时候,就相当于ImportBeanDefinitionRegistrar接口的实现类被实例化了,这个ImportBeanDefinitionRegistrar接口,相信熟悉spring的同学对其不会陌生,它是用来动态注册bean的,那么接下来的重点就是ImportBeanDefinitionRegistrar的registerBeanDefinitions方法的具体内容,看看它到底注册了什么bean
-
registerBeanDefinitions方法的代码在AbstractRetrofitClientsRegistrar.java中(请在上面的类图中找到AbstractRetrofitClientsRegistrar的位置),如下所示,由于EnableRetrofitClients修饰的是咱们创建的OkHttpClientConfig.java,所以下面的入参AnnotationMetadata是OkHttpClientConfig类的注解信息:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerRetrofitClients(metadata, registry);
}
-
上述代码的第一个方法registerDefaultConfiguration是注册配置信息的,非重点,跳过
-
上述代码的第二个方法registerRetrofitClients,这是本篇的关键,请重点关注下面代码中的中文注释:
public void registerRetrofitClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set basePackages;
Map<String, Object> attrs = metadata.getAnnotationAttributes(getAnnotationClass().getName());
// 过滤条件:有RetrofitClient注解修饰的类,对应咱们代码中的HelloService.java
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(RetrofitClient.class);
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get(“clients”);
if (clients == null || clients.length == 0) {
scanner.addIncludeFilter(annotationTypeFilter);
basePackages = getBasePackages(metadata);
}
else {
final Set clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll(“\$”, “.”);
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(new AllTypeFi