这两个内容源码虽然不算少,但是内容不太重要,在其他的 Module 里应用到了再做具体的学习。
1.spring-jcl
- jcl 的全称为 Jakarta commons-logging,原是 apache 提供的一个抽象的日志框架,并不提供日志功能,若需要使用具体的日志则需要添加依赖的 jar 包,由于 jcl 的自我抛弃,不再进行维护了。但是框架总归是要记录日志的。所以 spring 5.0.x 框架封装了一个 jcl 框架 spring-jcl。
1.1.日志加载
spring-jcl 对外提供统一的接口,对日志的操作委托给具体的日志框架,5.0.2.RELEASE 版本中支持的日志如下:
private enum LogApi {LOG4J, SLF4J_LAL, SLF4J, JUL}
其中 JUL 为 java.util.logging ,JDK提供的基础日志功能,默认为 JUL,其他日志功能需要引入对应依赖。
静态块在类进行加载的时候就会尝试加载上述日志框架。当调用 LogFactory 工厂的 getLog 静态方法时,根据对应日志框架名称,创建对应日志类,部分源码如下:
public abstract class LogFactory {
private static LogApi logApi = LogApi.JUL;
static {
ClassLoader cl = LogFactory.class.getClassLoader();
try {
// Try Log4j 2.x API
cl.loadClass("org.apache.logging.log4j.spi.ExtendedLogger");
logApi = LogApi.LOG4J;
}
catch (ClassNotFoundException ex1) {
try {
// Try SLF4J 1.7 SPI
cl.loadClass("org.slf4j.spi.LocationAwareLogger");
logApi = LogApi.SLF4J_LAL;
}
catch (ClassNotFoundException ex2) {
try {
// Try SLF4J 1.7 API
cl.loadClass("org.slf4j.Logger");
logApi = LogApi.SLF4J;
}
catch (ClassNotFoundException ex3) {
// Keep java.util.logging as default
}
}
}
}
public static Log getLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jDelegate.createLog(name);
case SLF4J_LAL:
return Slf4jDelegate.createLocationAwareLog(name);
case SLF4J:
return Slf4jDelegate.createLog(name);
default:
// Defensively use lazy-initializing delegate class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
return JavaUtilDelegate.createLog(name);
}
}
}
该源码比较与 apache 的 jcl 简化了很多,核心类只有 LogFactory。
2.spring-core
spring核心包,主要包含 Spring 框架基本的核心工具类, Spring 的其他纽件都要用到这个包里的类, Core 模块是其他纽件的基本核心。
编译 spring-core 报错:找不到 DefaultNamingPolicy,Objenesis 类:为了避免第三方 class 的冲突,Spring 把最新的 cglib 和 objenesis 重新打包,并没有再源码提供这部分的代码,在官方文档里注释:这种重新打包技术避免了与应用程序级或第三方库和框架中不同 Objensis 版本之间的依赖关系的任何潜在冲突。
解决办法:在IDEA中打开右侧边栏的gradle,找到 Tasks --- other 模块,分别双击 cglibRepackJar 和 objenesisRepackJar 将两部分重新打包即可。或者也可以手动在 spring-core.gradle 配置文件中的 dependcies 配置项末尾添加:
dependencies {
cglib("cglib:cglib:${cglibVersion}@jar")
objenesis("org.objenesis:objenesis:${objenesisVersion}@jar")
jarjar("com.googlecode.jarjar:jarjar:1.3")
compile(files(cglibRepackJar))
compile(files(objenesisRepackJar))
compile(project(":spring-jcl"))
optional("net.sf.jopt-simple:jopt-simple:5.0.4")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
optional("io.projectreactor:reactor-core")
optional("io.reactivex:rxjava:${rxjavaVersion}")
optional("io.reactivex:rxjava-reactive-streams:${rxjavaAdapterVersion}")
optional("io.reactivex.rxjava2:rxjava:${rxjava2Version}")
optional("io.netty:netty-buffer")
testCompile("io.projectreactor:reactor-test")
testCompile("javax.xml.bind:jaxb-api:2.3.0")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("com.fasterxml.woodstox:woodstox-core:5.0.3") {
exclude group: "stax", module: "stax-api"
}
compile fileTree(dir: 'libs', include : '*.jar') //添加该行
}
重新导入即可。
2.1.目录结构
asm:一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类
cglib:一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为 jdk 的动态代理提供了很好的补充。通常可以使用 Java 的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,cglib 是一个好的选择
core:核心包
- 根目录:别名注册、属性访问。
- annotation:注解、元注解、合并的注解等。
- codec:encode 和 decode 输入流 (主要用于编解码) 。
- convert:主要是转换器服务,将一个类型转换位另外一个类型。
- env:系统环境 (jdk环境参数:System.getProperties()、System.getenv())。
- io:访问资源(主要是文件系统,也有字节流、jboss VFS)的工具
- serializer:java 对象的字节流序列化和反序列化工具。
- style:用来控制 java 对象输出为 String 的风格。
- task:封装了一套同步和异步执行任务的 executor (并未使用线程池)。
- type:访问 class meta 的工具。
lang:注解定义
objenesis:用于实例化一个特定 class 的对象,在类库中经常会有类必须拥有一个默认构造器的限制。Objenesis 通过绕开对象实例构造器来克服这个限制。常见使用场景有:
序列化,远程调用和持久化对象需要实例化并存储为到一个特殊的状态,而没有调用代码
代理,AOP 库和 Mock 对象,类可以被子类继承而子类不用担心父类的构造器
容器框架,对象可以以非标准的方式被动态实例化
util:工具类,这个包的工具类可以独立于 Spring 框架而存在;而 core 工具类主要还是为 Spring 框架所用,与 Spring 结合比较紧密。
2.2.源码说明
- 这里的部分并不常用,或者说其原理不是很重要,简单说明。
2.2.1.asm类解读
*Visitor 抽象类:包含 AnnotationVisitor、ClassVisitor、FieldVisitor、MethodVisitor、ModuleVisitor 五个抽象类:
- AnnotationVisitor:定义在解析注解时会触发的事件,如解析到一个基本值类型的注解、Enum 值类型的注解、Array 值类型的注解、注解值类型的注解等。
- ClassVisitor:定义在读取 Class 字节码时会触发的事件,如类头解析完成、注解解析、字段解析、方法解析等。
- FieldVisitor:定义在解析字段时触发的事件,如解析到字段上的注解、解析到字段相关的属性等。
- MethodVisitor:定义在解析方法时触发的事件,如方法上的注解、属性、代码等。
- ModuleVisitor:定义在访问 Module 时触发的事件,如访问包等。
*Writer:包含 AnnotationWriter、ClassWriter、FieldWriter、MethodWriter、ModuleWriter 五个类,分别继承上述对应的 *Visitor 抽象类,用于生成上述对应类型的二进制字节码。
- ClassReader:类的读取解析。
- Attribute:字节码中属性的类抽象。
- ByteVector:字节码二进制存储的容器。
- Opcodes:字节码指令的一些常量定义。
- Type*:类型相关的常量定义以及一些基于其上的操作。
2.2.2.core
annotation:注解、元注解、合并的注解等,注解相关的类和操作都在该包下,主要包含两大部分,一部分是关于 @AliasFor 注解的定义及其相关的使用说明,如AnnotationUtils,AnnotationAttributes 等类都是为了 @AliasFor 注解的使用做出的相关配套设施,另一部分是 @Order 类及其相关配套:
第一部分:@AliasFor 及其部分相关配套
@AliasFor:该注解相关信息必须通过 AnnotationUtils 加载,通常有以下几种用法:
别名,在注解定义中的属性上使用,如 @RequestMapping 注解的 path 和 value 属性,指定其中一个即指定了另一个:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
继承父注解的属性,不重写属性名,子注解的属性值的读写,其实是对父注解的属性值的读写,如@Service、@Controller 等价于 @Component:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component //注意要声明父注解
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component //注意要声明父注解
public @interface Controller {
@AliasFor(annotation = Component.class)
String value() default "";
}
继承父注解的属性,并重写属性名,需指定父注解的类型以及具体的属性,子注解的属性值的读写,其实是对父注解的属性值的读写,若两个都指明属性值,要求值必须相同,否则会报错。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Inherited
public @interface MyAnnotation {
@AliasFor(attribute = "location")
String value() default "";
@AliasFor(attribute = "value")
String location() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Inherited
@MyAnnotation //注意要声明父注解
public @interface SubMyAnnotation {
@AliasFor(attribute = "value", annotation = MyAnnotation.class)
String subValue() default "";
@AliasFor(attribute = "location", annotation = MyAnnotation.class)
String subLocation() default "";
// subLocation属性写成下边这两种结果是一样的
// @AliasFor(attribute = "value", annotation = MyAnnotation.class)
// String subLocation() default "";
// @AliasFor(value = "location", annotation = MyAnnotation.class)
// String subLocation() default "";
//
}
注解的叠加复用,如@SpringBootApplication,在注解定义上配置需要复用的注解,并在指定属性上声明复用的注解属性 (本质上还是相当于实现了注解的继承功能):
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
//复用@EnableAutoConfiguration注解的exclude属性
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
//复用@EnableAutoConfiguration注解的excludeName属性
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
//复用@ComponentScan的basePackages属性
@AliasFor(annotation = ComponentScan.class,attribute = "basePackages")
String[] scanBasePackages() default {};
//复用@ComponentScan的basePackageClasses属性
@AliasFor(annotation = ComponentScan.class,attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
@AliasFor 注解需要通过 Spring 中提供的工具类 AnnotationUtils 或 AnnotatedElementUtils 来解析才能生效。AnnotatedElementUtils 内部还是调用的 AnnotationUtils。互为别名的属性值,使用的时候如果均赋值,同时又通过 AnnotationUtils 的 findAnnotation 方法获取属性值,那么会抛出异常。Spring 其实是自己实现了 jdk 动态的拦截器来实现别名功能。
@RequestMapping("/test")
public class App{}
@Test
public void test(){
RequestMapping springAnnotationProxy = AnnotationUtils.findAnnotation(App.class, RequestMapping.class);
System.out.println("springAnnotationProxy path:" + springAnnotationProxy.path());
System.out.println("springAnnotationProxy value:" + springAnnotationProxy.value());
RequestMapping jdkAnnotation = App.class.getAnnotation(RequestMapping.class);
System.out.println("jdkAnnotation path:" + jdkAnnotation.path());
System.out.println("jdkAnnotation value:" + jdkAnnotation.value());
}
debug 功能可以看出,springAnnotationProxy 的底层类型是 SynthesizedAnnotationInvocationHandler,其 value 和 path 属性值均为 test,而 jdkAnnotation 的底层类型是 AnnotationInvocationHandler,其只有 value 属性值为 test,path 属性为空。
AnnotationAttributes:本质上是一个 Map<String, Object> 集合,继承 LinkedHashMap,用于保存某个注解实例的全部属性 (属性名和对应的属性值) 。
AnnotationAwareOrderComparator:对 OrderComparator 的增强 (继承) ,可以对 Ordered 对象、使用 @Order 注解的对象进行比较。与OrderComparator 一样提供了如上两个静态的排序方法。
AnnotationUtils 中包含了很多解析注解的方法:
public static <A extends Annotation> A getAnnotation(Annotation ann, Class<A> annotationType)
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType)
public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType)
public static Annotation[] getAnnotations(AnnotatedElement annotatedElement)
public static Annotation[] getAnnotations(Method method)
// 获取函数上或注解上的注解
- public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType)
public static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> annotationType)
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType)
递归查找父注解
- public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz)
public static boolean isAnnotationInherited(Class<? extends Annotation> annotationType, Class<?> clazz)
public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annotationType, @Nullable Class<? extends Annotation> metaAnnotationType)
是否声明了/继承了某个注解
- public static Map<String, Object> getAnnotationAttributes(Annotation annotation)
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString)
public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement, Annotation annotation)
获取注解的所有属性,返回 AnnotationAttributes
- public static Object getValue(Annotation annotation)
public static Object getValue(@Nullable Annotation annotation, @Nullable String attributeName)
public static Object getDefaultValue(Annotation annotation)
public static Object getDefaultValue(@Nullable Annotation annotation, @Nullable String attributeName)
public static Object getDefaultValue(Class<? extends Annotation> annotationType)
public static Object getDefaultValue(@Nullable Class<? extends Annotation> annotationType, @Nullable String attributeName)
获取注解的值以及默认值
第二部分:@Order 及其部分相关配套
- @Order:@Order 注解定义了类、方法和字段的优先级(排序情况),value 是可选的,默认为 Ordered.LOWEST_PRECEDENCE,即最低优先级。表示 Ordered 接口中的 order 属性。
- OrderUtils:主要用于获取 @Order 注解的相关属性。
- OrderComparator(根目录下):Ordered 对象的比较器,对外提供了两个静态的排序方法
public static void sort(List<?> list)、public static void sort(Object[] array)。
codec:编解码工具,不常用,略
convert:主要用于类型转换
TypeDescriptor:对java中所有数据类型的描述,包括 Collection、Map、自定义 Object、数组、基本数据类型及其包装类型。它被成对地用于GenericConversionService 中,表示从 src 类型到 target 类型的转换,会有一个相应的 converter 实现与之对应。为了提高性能,对基本数据类型及其包装类型做了缓存。
DefaultConversionService:对外提供的 API 的主要服务类
env:提供一个代表系统环境的 StandardEnvironment,包括对 System.getProperties()、System.getenv() 的访问。在 Spring Web 中StandardServletEnvironment 继承了 StandardEnvironment,又增加对 Servlet 容器系统参数的访问。
io:供外部调用的入口API主要是 FileSystemResourceLoader、ClassRelativeResourceLoader。spring web、spring context 等模块也会自定义覆盖/实现ResourceLoader的子类和子接口。
serializer: java 对象的字节流序列化和反序列化
style:略
task:实现了两个适配器,分别是
并提供了一个简单的异步 TaskExecutor 的实现 SimpleAsyncTaskExecutor。它继承 CustomizableThreadCreator,用来创建线程并给线程命名(有意义的名字),需要注意的是它并没有使用线程池。ConcurrencyThrottleSupport 在 SimpleAsyncTaskExecutor 中用于控制并发,应用了生产者-消费者模式。
- TaskExecutorAdapter:将 Executor 适配为 TaskExecutor
- ExecutorServiceAdapter,将 TaskExecutor 适配为 Executor/ExecutorService。
type:对外暴露的、可直接使用的API接口为 CachingMetadataReaderFactory。基于 ASM,使用了访问者设计模式,同时使用 cache 来避免了对 class 的重复加载和解析。
根目录的部分其他类:
- AliasRegistry、SimpleAliasRegistry:别名注册,保存的是Map from alias to canonical name,解决了别名循环的问题。
- CollectionFactory:提供了几个静态函数,Collection createCollection(Class collectionType, int initialCapacity),Map createMap(Class mapType, int initialCapacity) 等等。
- Constants:提供了对一个类中 public static final 且名字为大写的字段的访问。
- ControlFlow、ControlFlowFactory:判断当前运行的堆栈中是否包含某个class或某个函数。
- DecoratingClassLoader:供其他包来继承的一个抽象类,加载时可以让使用者有选择的排除掉某些class和某些package下的class。
- ExceptionDepthComparator:用来比较exception和targetException深度的比较器。对外提供了一个静态工具方法:Class<? extends Throwable> findClosestMatch(Collection<Class<? extends Throwable>> exceptionTypes, Throwable targetException)
- GenericCollectionTypeResolver:一个很有用、很强大的工具类,用来获取Collection中元素的类型、Map中的Key/Value类型。
- GenericTypeResolver:工具类,获取函数的参数类型、返回类型。
- LocalVariableTableParameterNameDiscoverer、ParameterNameDiscoverer:基于ASM,获取函数和构造器的参数名字。
- SpringProperties:加载spring.properties到Properties中,并访问其中的属性。
2.2.3.util
- BooleanComparator:对 Boolean 数据进行排序(顺序和逆序)用到的比较器;
- ComparableComparator:适配 Comparable 的 Comparator。
- CompoundComparator:组合模式。多个 Comparator 组合成一个 Comparator
- InstanceComparator:基于任意类顺序比较对象。
- InvertibleComparator:可逆的比较器 (装饰者设计模式)。
- NullSafeComparator:将一个只能对非 null 对象排序的比较器,装饰成一个可以对 null 对象排序的比较器 (装饰者设计模式)。
- ClassUtils:class 工具类。包括装载 class,访问 class 名字、包名、函数、构造器、class类型是否是基本类型、接口等等。
- CollectionUtils:封装了少数几个集合工具的静态方法。
- CompositeIterator:多个迭代期组合到一起的迭代期,使用了组合设计模式。
- ConcurrentReferenceHashMap:与 ConcurrentHashMap 不同的是,它的 key 和 value 存的是是软引用或弱引用 (可在构造器中指定)
- PropertiesPersister、DefaultPropertiesPersister:实现了对 Properties 的加载和存储。
- FileCopyUtils:在File、byte[]、IO流之间的转换。
- FileSystemUtils:对文件、文件夹的递归删除和递归拷贝。
- LinkedCaseInsensitiveMap:对 key 大小写不敏感的 LinkedHashMap 实现。
- LinkedMultiValueMap:一个 key 映射多个 value 的 Map 结构。
- MethodInvoker:将方法、object、class、方法参数封装进来,以供该方法的调用。
- NumberUtils:将 String 转为制定类型的 Number。
- ObjectUtils:实现了 基本数据类型及其数组的 hashcode,基本数据类型及其数组的 toString() 方法等等。
- PropertyPlaceholderHelper:提供了两个重载函数 replacePlaceholders,用来替换字符串 value 中中的占位符。
- ReflectionUtils:提供了访问field、method、函数调用等工具方法。
- SerializationUtils:java 序列化和反序列化
- ResourceUtils:用于将资源位置解析为文件系统中的文件的实用工具方法。
- StopWatch:对任务执行时间的统计,包括总时间、每个任务的执行时间。
- StreamUtils:IO 字节流和字节数组之间的拷贝。
- StringUtils:字符串为空、长度、trim 操作、等等。
- SystemPropertyUtils:与 PropertyPlaceholderHelper 不同的是,它使用 System.getProperty() 来替换占位符。
- TypeUtils:boolean isAssignable(Type lhsType, Type rhsType)
2.2.4.cglib&langobjenesis
- 这里主要引用了一些 jar 包以及部分类的声明,内容很少,不再赘述。
以上就是Spring jcl及spring core源码深度解析的详细内容,更多关于Spring jcl spring core解析的资料请关注编程网其它相关文章!