欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring jcl及spring core源碼深度解析

 更新時間:2022年11月02日 09:21:05   作者:Lemonade22  
這篇文章主要為大家介紹了Spring jcl及spring core源碼深度解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

這兩個內(nèi)容源碼雖然不算少,但是內(nèi)容不太重要,在其他的 Module 里應用到了再做具體的學習。

1.spring-jcl

  • jcl 的全稱為 Jakarta commons-logging,原是 apache 提供的一個抽象的日志框架,并不提供日志功能,若需要使用具體的日志則需要添加依賴的 jar 包,由于 jcl 的自我拋棄,不再進行維護了。但是框架總歸是要記錄日志的。所以 spring 5.0.x 框架封裝了一個 jcl 框架 spring-jcl。

1.1.日志加載

spring-jcl 對外提供統(tǒng)一的接口,對日志的操作委托給具體的日志框架,5.0.2.RELEASE 版本中支持的日志如下:

private enum LogApi {LOG4J, SLF4J_LAL, SLF4J, JUL}

其中 JUL 為 java.util.logging ,JDK提供的基礎日志功能,默認為 JUL,其他日志功能需要引入對應依賴。

靜態(tài)塊在類進行加載的時候就會嘗試加載上述日志框架。當調(diào)用 LogFactory 工廠的 getLog 靜態(tài)方法時,根據(jù)對應日志框架名稱,創(chuàng)建對應日志類,部分源碼如下:

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 字節(jié)碼操控框架。它能夠以二進制形式修改已有類或者動態(tài)生成類。ASM 可以直接產(chǎn)生二進制 class 文件,也可以在類被加載入 Java 虛擬機之前動態(tài)改變類行為。ASM 從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類

cglib:一個功能強大,高性能的代碼生成包。它為沒有實現(xiàn)接口的類提供代理,為 jdk 的動態(tài)代理提供了很好的補充。通??梢允褂?Java 的動態(tài)代理創(chuàng)建代理,但當要代理的類沒有實現(xiàn)接口或者為了更好的性能,cglib 是一個好的選擇

core:核心包

  • 根目錄:別名注冊、屬性訪問。
  • annotation:注解、元注解、合并的注解等。
  • codec:encode 和 decode 輸入流 (主要用于編解碼) 。
  • convert:主要是轉換器服務,將一個類型轉換位另外一個類型。
  • env:系統(tǒng)環(huán)境 (jdk環(huán)境參數(shù):System.getProperties()、System.getenv())。
  • io:訪問資源(主要是文件系統(tǒng),也有字節(jié)流、jboss VFS)的工具
  • serializer:java 對象的字節(jié)流序列化和反序列化工具。
  • style:用來控制 java 對象輸出為 String 的風格。
  • task:封裝了一套同步和異步執(zhí)行任務的 executor (并未使用線程池)。
  • type:訪問 class meta 的工具。

lang:注解定義

objenesis:用于實例化一個特定 class 的對象,在類庫中經(jīng)常會有類必須擁有一個默認構造器的限制。Objenesis 通過繞開對象實例構造器來克服這個限制。常見使用場景有:

序列化,遠程調(diào)用和持久化對象需要實例化并存儲為到一個特殊的狀態(tài),而沒有調(diào)用代碼

代理,AOP 庫和 Mock 對象,類可以被子類繼承而子類不用擔心父類的構造器

容器框架,對象可以以非標準的方式被動態(tài)實例化

util:工具類,這個包的工具類可以獨立于 Spring 框架而存在;而 core 工具類主要還是為 Spring 框架所用,與 Spring 結合比較緊密。

2.2.源碼說明

  • 這里的部分并不常用,或者說其原理不是很重要,簡單說明。

2.2.1.asm類解讀

*Visitor 抽象類:包含 AnnotationVisitor、ClassVisitor、FieldVisitor、MethodVisitor、ModuleVisitor 五個抽象類:

  • AnnotationVisitor:定義在解析注解時會觸發(fā)的事件,如解析到一個基本值類型的注解、Enum 值類型的注解、Array 值類型的注解、注解值類型的注解等。
  • ClassVisitor:定義在讀取 Class 字節(jié)碼時會觸發(fā)的事件,如類頭解析完成、注解解析、字段解析、方法解析等。
  • FieldVisitor:定義在解析字段時觸發(fā)的事件,如解析到字段上的注解、解析到字段相關的屬性等。
  • MethodVisitor:定義在解析方法時觸發(fā)的事件,如方法上的注解、屬性、代碼等。
  • ModuleVisitor:定義在訪問 Module 時觸發(fā)的事件,如訪問包等。

*Writer:包含 AnnotationWriter、ClassWriter、FieldWriter、MethodWriter、ModuleWriter 五個類,分別繼承上述對應的 *Visitor 抽象類,用于生成上述對應類型的二進制字節(jié)碼。

  • ClassReader:類的讀取解析。
  • Attribute:字節(jié)碼中屬性的類抽象。
  • ByteVector:字節(jié)碼二進制存儲的容器。
  • Opcodes:字節(jié)碼指令的一些常量定義。
  • 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 {
    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     */
    @AliasFor(annotation = Component.class)
    String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component  //注意要聲明父注解
public @interface Controller {
    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     */
    @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,在注解定義上配置需要復用的注解,并在指定屬性上聲明復用的注解屬性 (本質(zhì)上還是相當于實現(xiàn)了注解的繼承功能):

@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 內(nèi)部還是調(diào)用的 AnnotationUtils。互為別名的屬性值,使用的時候如果均賦值,同時又通過 AnnotationUtils 的 findAnnotation 方法獲取屬性值,那么會拋出異常。Spring 其實是自己實現(xiàn)了 jdk 動態(tài)的攔截器來實現(xiàn)別名功能。

@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:本質(zhì)上是一個 Map<String, Object> 集合,繼承 LinkedHashMap,用于保存某個注解實例的全部屬性 (屬性名和對應的屬性值) 。

AnnotationAwareOrderComparator:對 OrderComparator 的增強 (繼承) ,可以對 Ordered 對象、使用 @Order 注解的對象進行比較。與OrderComparator 一樣提供了如上兩個靜態(tài)的排序方法。

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)
// 獲取函數(shù)上或注解上的注解
        -   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 注解定義了類、方法和字段的優(yōu)先級(排序情況),value 是可選的,默認為 Ordered.LOWEST_PRECEDENCE,即最低優(yōu)先級。表示 Ordered 接口中的 order 屬性。

-   OrderUtils:主要用于獲取 @Order 注解的相關屬性。

-   OrderComparator(根目錄下):Ordered 對象的比較器,對外提供了兩個靜態(tài)的排序方法

public static void sort(List<?> list)、public static void sort(Object[] array)。

codec:編解碼工具,不常用,略

convert:主要用于類型轉換

TypeDescriptor:對java中所有數(shù)據(jù)類型的描述,包括 Collection、Map、自定義 Object、數(shù)組、基本數(shù)據(jù)類型及其包裝類型。它被成對地用于GenericConversionService 中,表示從 src 類型到 target 類型的轉換,會有一個相應的 converter 實現(xiàn)與之對應。為了提高性能,對基本數(shù)據(jù)類型及其包裝類型做了緩存。

DefaultConversionService:對外提供的 API 的主要服務類

env:提供一個代表系統(tǒng)環(huán)境的 StandardEnvironment,包括對 System.getProperties()、System.getenv() 的訪問。在 Spring Web 中StandardServletEnvironment 繼承了 StandardEnvironment,又增加對 Servlet 容器系統(tǒng)參數(shù)的訪問。

io:供外部調(diào)用的入口API主要是 FileSystemResourceLoader、ClassRelativeResourceLoader。spring web、spring context 等模塊也會自定義覆蓋/實現(xiàn)ResourceLoader的子類和子接口。

serializer: java 對象的字節(jié)流序列化和反序列化

style:略

task:實現(xiàn)了兩個適配器,分別是

并提供了一個簡單的異步 TaskExecutor 的實現(xiàn) SimpleAsyncTaskExecutor。它繼承 CustomizableThreadCreator,用來創(chuàng)建線程并給線程命名(有意義的名字),需要注意的是它并沒有使用線程池。ConcurrencyThrottleSupport 在 SimpleAsyncTaskExecutor 中用于控制并發(fā),應用了生產(chǎn)者-消費者模式。

  • TaskExecutorAdapter:將 Executor 適配為 TaskExecutor
  • ExecutorServiceAdapter,將 TaskExecutor 適配為 Executor/ExecutorService。

type:對外暴露的、可直接使用的API接口為 CachingMetadataReaderFactory?;?ASM,使用了訪問者設計模式,同時使用 cache 來避免了對 class 的重復加載和解析。

根目錄的部分其他類:

  • AliasRegistry、SimpleAliasRegistry:別名注冊,保存的是Map from alias to canonical name,解決了別名循環(huán)的問題。
  • CollectionFactory:提供了幾個靜態(tài)函數(shù),Collection createCollection(Class collectionType, int initialCapacity),Map createMap(Class mapType, int initialCapacity) 等等。
  • Constants:提供了對一個類中 public static final 且名字為大寫的字段的訪問。
  • ControlFlow、ControlFlowFactory:判斷當前運行的堆棧中是否包含某個class或某個函數(shù)。
  • DecoratingClassLoader:供其他包來繼承的一個抽象類,加載時可以讓使用者有選擇的排除掉某些class和某些package下的class。
  • ExceptionDepthComparator:用來比較exception和targetException深度的比較器。對外提供了一個靜態(tài)工具方法:Class<? extends Throwable> findClosestMatch(Collection<Class<? extends Throwable>> exceptionTypes, Throwable targetException)
  • GenericCollectionTypeResolver:一個很有用、很強大的工具類,用來獲取Collection中元素的類型、Map中的Key/Value類型。
  • GenericTypeResolver:工具類,獲取函數(shù)的參數(shù)類型、返回類型。
  • LocalVariableTableParameterNameDiscoverer、ParameterNameDiscoverer:基于ASM,獲取函數(shù)和構造器的參數(shù)名字。
  • SpringProperties:加載spring.properties到Properties中,并訪問其中的屬性。

2.2.3.util

  • BooleanComparator:對 Boolean 數(shù)據(jù)進行排序(順序和逆序)用到的比較器;
  • ComparableComparator:適配 Comparable 的 Comparator。
  • CompoundComparator:組合模式。多個 Comparator 組合成一個 Comparator
  • InstanceComparator:基于任意類順序比較對象。
  • InvertibleComparator:可逆的比較器 (裝飾者設計模式)。
  • NullSafeComparator:將一個只能對非 null 對象排序的比較器,裝飾成一個可以對 null 對象排序的比較器 (裝飾者設計模式)。
  • ClassUtils:class 工具類。包括裝載 class,訪問 class 名字、包名、函數(shù)、構造器、class類型是否是基本類型、接口等等。
  • CollectionUtils:封裝了少數(shù)幾個集合工具的靜態(tài)方法。
  • CompositeIterator:多個迭代期組合到一起的迭代期,使用了組合設計模式。
  • ConcurrentReferenceHashMap:與 ConcurrentHashMap 不同的是,它的 key 和 value 存的是是軟引用或弱引用 (可在構造器中指定)
  • PropertiesPersister、DefaultPropertiesPersister:實現(xiàn)了對 Properties 的加載和存儲。
  • FileCopyUtils:在File、byte[]、IO流之間的轉換。
  • FileSystemUtils:對文件、文件夾的遞歸刪除和遞歸拷貝。
  • LinkedCaseInsensitiveMap:對 key 大小寫不敏感的 LinkedHashMap 實現(xiàn)。
  • LinkedMultiValueMap:一個 key 映射多個 value 的 Map 結構。
  • MethodInvoker:將方法、object、class、方法參數(shù)封裝進來,以供該方法的調(diào)用。
  • NumberUtils:將 String 轉為制定類型的 Number。
  • ObjectUtils:實現(xiàn)了 基本數(shù)據(jù)類型及其數(shù)組的 hashcode,基本數(shù)據(jù)類型及其數(shù)組的 toString() 方法等等。
  • PropertyPlaceholderHelper:提供了兩個重載函數(shù) replacePlaceholders,用來替換字符串 value 中中的占位符。
  • ReflectionUtils:提供了訪問field、method、函數(shù)調(diào)用等工具方法。
  • SerializationUtils:java 序列化和反序列化
  • ResourceUtils:用于將資源位置解析為文件系統(tǒng)中的文件的實用工具方法。
  • StopWatch:對任務執(zhí)行時間的統(tǒng)計,包括總時間、每個任務的執(zhí)行時間。
  • StreamUtils:IO 字節(jié)流和字節(jié)數(shù)組之間的拷貝。
  • StringUtils:字符串為空、長度、trim 操作、等等。
  • SystemPropertyUtils:與 PropertyPlaceholderHelper 不同的是,它使用 System.getProperty() 來替換占位符。
  • TypeUtils:boolean isAssignable(Type lhsType, Type rhsType)

2.2.4.cglib&langobjenesis

  • 這里主要引用了一些 jar 包以及部分類的聲明,內(nèi)容很少,不再贅述。

以上就是Spring jcl及spring core源碼深度解析的詳細內(nèi)容,更多關于Spring jcl spring core解析的資料請關注腳本之家其它相關文章!

相關文章

最新評論