spring源码系列—resource抽象

怀瑾握瑜      2022-04-18     617

关键词:

前言

前面两篇介绍了上下文的启动流程和Environemnt的初始化,这两部分都是属于上下文自身属性的初始化。这篇开始进入Spring如何加载实例化Bean的部分 — 资源抽象与加载。

本文主要从以下方面介绍Spring中的资源Resource:

  • 前提准备
  • Resource抽象
  • Resource加载解析
  • 何时何地触发加载解析
  • 总结

前提准备

Spring中的资源抽象使用到了很多陌生的api,虽然这些api都是JDK提供,但是日常的业务场景中很少使用或者接触不深。在阅读Resource的源码前,需要完善知识体系,减轻阅读Resource实现的难度。

1.URL和URI

URL代表Uniform Resource Locator,指向万维网上的一个资源。资源可以是文件、声音、视频等。
URI代表Uniform Resource Identifier,用于标识一个特定资源。URL是URI的一种,也可以用于标识资源。

URI的语法如下:

不在第一条直线上的部分都是可选。关于更多URL和URI的详细信息可以参考URLURI

在Java中提供了两个类分别表示URL和URI。两者在描述资源方面提供了很多相同的属性:protocol(scheme)/host/port/file(path)等等。但是URL除此还提供了建立Tcp连接,获取Stream的操作。如:

public URLConnection openConnection() throws java.io.IOException {
    return handler.openConnection(this);
}

public final InputStream openStream() throws java.io.IOException {
    return openConnection().getInputStream();
}

因为URL表示网络中的资源路径,所以它能够提供网络操作获取资源。Spring中包含UrlResource即是对URL的封装,提供获取资源的便捷性。

2.Class和ClassLoader

Class是Java中对象类型。Class对象提供了加载资源的能力,根据资源名称搜索,返回资源的URL:

public java.net.URL getResource(String name) {
	...省略
}

ClassLoader是类加载器,它同样也提供了加载资源的能力:

// 搜索单个资源
public URL getResource(String name) {
    ...省略
}

// 搜索匹配的多个资源
public Enumeration<URL> getResources(String name) throws IOException {
    ...省略
}

Class中getResource委托加载该Class的ClassLoader搜索匹配的资源。搜索规则:委托父类加载器搜索,父类加载器为空再有启动类加载器搜索。搜索结果为空,再由该类加载器的findResources搜索。

在Spring中,加载类路径上的资源就由ClassLoader.getResources完成。

3.URLClassLoader

URLClassLoader是Java中用于从搜索路径上加载类和资源,搜索路径包括JAR文件和目录。
在Spring中利用其获得所有的搜索路径—即JAR files和目录,然后从目录和JAR files中搜索匹配特定的资源。如:
Spring支持Ant风格的匹配,当搜索模式*.xml的资源时,无法通过classLoader.getResources获取,故Spring自实现获取匹配该模式的资源。

URLClassLoader提供接口获取所有的搜索路径:

/**
 * Returns the search path of URLs for loading classes and resources.
 * This includes the original list of URLs specified to the constructor,
 * along with any URLs subsequently appended by the addURL() method.
 * @return the search path of URLs for loading classes and resources.
 */
public URL[] getURLs() {
    return ucp.getURLs();
}
3.JarFile和JarEntry

对于JarFile和JarEntry类,笔者自己也未曾在工作中使用过。不过从命名上也可以看出一些猫腻。
JarFile用于表示一个Jar,可以利用其api读取Jar中的内容。
JarEntry用于表示Jar文件中的条目,比如:org/springframework/context/ApplicationContext.class

通过JarFile提供的entries接口可以获取jar文件中所有的条目:

public Enumeration<JarEntry> entries() {
    return new JarEntryIterator();
}

通过遍历条目,可以达到从Jar文件中检索需要的条目,即class。

4.JarURLConnection

同上,笔者之前也曾为接触JarURLConnection。JarURLConnection是URLConnection的实现类,表示对jar文件或者jar文件中的条目的URL连接。提供了获取输入流的能力,例外还提供获取JarFile对象的api。

语法如下:

jar:<url>!/{entry}

jar表示文件类型为jar,url表示jar文件位置,"!/"表示分隔符。

例如:

// jar条目
jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class

// jar文件
jar:http://www.foo.com/bar/baz.jar!/

// jar目录
jar:http://www.foo.com/bar/baz.jar!/COM/foo/

JarURLConnection提供获取JarFile和JarEntry对象的api:

public abstract JarFile getJarFile() throws IOException;

public JarEntry getJarEntry() throws IOException {
    return getJarFile().getJarEntry(entryName);
}

Tips
在Spring的Resource实现中,主要使用到了这些平时很少使用的陌生api。在阅读Resource实现前,非常有必要熟悉这些api。

Resource抽象

在Spring中的资源的抽象非常复杂,根据资源位置的不同,分别实现了纷繁复杂的资源。整体Resource的UML类图如下:

Note:
Spring中Resource模块使用了策略模式,上层实现统一的资源抽象接口,针对不同的Resource类型,分别封装各自的实现,然后在相应的场景中组合使用相应的资源类型。其中对于多态、继承的应用可谓淋漓尽致。

从以上的UML类图中可以看出:

  1. 将输入流作为源头的对象抽象为接口,可以表示输入流源;
  2. Spring统一抽象Resource接口,表示应用中的资源,如文件或者类路径上的资源。Resource继承上述的输入流源,则Resource抽象具有获取资源内容的能力;
  3. 在上图的下部,分别是Resource接口的具体实现。根据资源的表示方式不同,分为:
    文件系统Resource、字节数组Resource、URL的Resource、类路劲上的Resource等等;
1.UrlResource

UrlResource通过包装URL对象达到方位目标资源,目标资源包括:file、http网络资源、ftp文件资源等等。URL协议类型:"file:"文件系统、"http:"http协议、"ftp:"ftp协议。

pulic class UrlResource extends AbstractFileResolvingResource {
   private final URI uri;

   // 代表资源位置的url
   private final URL url;

	// 通过uri构造UrlResource对象
   public UrlResource(URI uri) throws MalformedURLException {
       Assert.notNull(uri, "URI must not be null");
       this.uri = uri;
       this.url = uri.toURL();
       this.cleanedUrl = getCleanedUrl(this.url, uri.toString());
   }
   // 通过url构造UrlResource对象
   public UrlResource(URL url) {
       Assert.notNull(url, "URL must not be null");
       this.url = url;
       this.cleanedUrl = getCleanedUrl(this.url, url.toString());
       this.uri = null;
   }
   // 通过path路径构造UrlResource对象
   public UrlResource(String path) throws MalformedURLException {
       Assert.notNull(path, "Path must not be null");
       this.uri = null;
       this.url = new URL(path);
       this.cleanedUrl = getCleanedUrl(this.url, path);
   }

   ...省略
}
2.ClassPathResource

ClassPathResource代表类路径资源,该资源可以由类加载加载。如果该资源在文件系统中,则支持使用getFile接口获取该资源对应的File对象;如果该资源在jar文件中但是无法扩展至文件系统中,则不支持解析为File对象,此时可以使用URL加载。

public class ClassPathResource extends AbstractFileResolvingResource {
    // 文件在相对于类路径的路径
    private final String path;
    // 指定类加载器
    private ClassLoader classLoader;
    private Class<?> clazz;

    public ClassPathResource(String path) {
        this(path, (ClassLoader) null);
    }
    public ClassPathResource(String path, ClassLoader classLoader) {
        Assert.notNull(path, "Path must not be null");
        String pathToUse = StringUtils.cleanPath(path);
        if (pathToUse.startsWith("/")) {
            pathToUse = pathToUse.substring(1);
        }
        this.path = pathToUse;
        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    }
}
3.FileSystemResource

FileSystemResource代表文件系统上的资源。可以通过getFile和getURL接口获取对应的File和URL对象。

public class FileSystemResource extends AbstractResource implements WritableResource {
    // 代表资源的File对象
    private final File file;
    // 文件系统路径
    private final String path;

    public FileSystemResource(File file) {
        Assert.notNull(file, "File must not be null");
        this.file = file;
        this.path = StringUtils.cleanPath(file.getPath());
    }
    public FileSystemResource(String path) {
        Assert.notNull(path, "Path must not be null");
        this.file = new File(path);
        this.path = StringUtils.cleanPath(path);
    }
}
4.ByteArrayResource

ByteArrayResource将字节数组byte[]包装成Resource。

5.InputStreamResource

InputStreamResource将输入流InputStream包装成Resource对象。

Spring文档Tips:
虽然Resouce为Spring框架设计和被Spring框架内部大量使用。但是Resource还可以作为通用的工具模块使用,日常的应用开发过程中涉及到资源的处理,推荐使用Resource抽象,因为Resource提供了操作资源的便捷接口,可以简化对资源的操作。虽然耦合Spring,但是在Spring产品的趋势下,还会有耦合?

Resource加载解析

Resource加载是基于XML配置Spring上下文的核心基础模块。Spring提供了强大的加载资源的能力。可以分为两种模式:

  • 根据简单的资源路径,加载资源;
  • 根据复杂的的资源路径:Ant-Style、classpath:、classpath*:等等,解析如此复杂的资源路径,加载资源;

Spring依次抽象出ResourceLoader和ResourcePatternResolver两部分实现以上的两种情况:

  • ResourceLoader纯粹的加载资源;
  • ResourcePatternResolver负责解析复杂多样的资源路径并加载资源,它本身也是加载器的一种,实现ResourceLoader接口;

Note:
策略模式是一个传神的模式,在Spring中最让我感叹的两个模式之一,在Spring中随处可见,可能源于策略模式是真的易扩展而带来的随心所欲的应对各种场景带来的效果吧。这里定义策略接口ResourceLoader,根据不同的场景实现相应的资源加载器,是典型策略的应用方式。

Spring对加载资源定义顶层接口ResourecLoader:

public interface ResourceLoader {

    /** Pseudo URL prefix for loading from the class path: "classpath:" */
    String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

	 // 根据资源路径加载resource对象
    Resource getResource(String location);
    // ResourceLoader是利用java的类加载器实现资源的加载
    ClassLoader getClassLoader();
}

该接口是加载资源的策略接口,Spring中加载资源模块的最顶层定义。Spring应用需要配置各种各样的配置,这些决定上下文具有加载资源的能力。在Spring中所有上下文都继承了ResouceLoader接口,加载资源是Spring上下文的基本能力。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

统一的上下文接口继承了ResoucePatternResolver接口,间接继承了ResourceLoader。

从ResouceLoader的接口定义上也可以看出,ResourceLoader只能加载单个资源,功能比较简单。其有个默认实现DefaultResourceLoader,在看DefaultResourceLoader之前,首先了解DefaultResourceLoader的SPI。

Spring提供了ProtocolResolver策略接口,也是策略模式的应用,为了解决特定协议的资源解析。被用于DefaultResourceLoader,使其解析资源的能力得以扩展。

public interface ProtocolResolver {
	 // 根据特定路径解析资源
    Resource resolve(String location, ResourceLoader resourceLoader);
}

应用可以自实现该接口,将其实现加入,如:

/**
 * 实现对http协议URL资源的解析
 *
 * @author huaijin
 */
public class FromHttpProtocolResolver implements ProtocolResolver {

    @Override
    public Resource resolve(String location, ResourceLoader resourceLoader) {
        if (location == null || location.isEmpty() || location.startsWith("http://")) {
            return null;
        }
        byte[] byteArray;
        InputStream inputStream = null;
        try {
            URL url = new URL(location);
            inputStream = url.openStream();
            byteArray = StreamUtils.copyToByteArray(inputStream);
        } catch (MalformedURLException e) {
            throw new RuntimeException("location isn't legal url.", e);
        } catch (IOException e) {
            throw new RuntimeException("w/r err.", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new ByteArrayResource(byteArray);
    }
}


// 将其加入上下文容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
context.addProtocolResolver(new FromHttpProtocolResolver());

DefaultResouceLoader中部分源代码如下:

public class DefaultResourceLoader implements ResourceLoader {

    // 类加载器,可以编程式设置
    private ClassLoader classLoader;

    // 协议解析器集合
    private final Set<ProtocolResolver> protocolResolvers = new LinkedHashSet<ProtocolResolver>(4);

    // 增加协议解析器
    public void addProtocolResolver(ProtocolResolver resolver) {
        Assert.notNull(resolver, "ProtocolResolver must not be null");
        this.protocolResolvers.add(resolver);
    }


    // 加载单个资源实现
    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");

        // 遍历资源解析器,使用解析器加载资源,如果加载成功,则返回资源
        for (ProtocolResolver protocolResolver : this.protocolResolvers) {
            Resource resource = protocolResolver.resolve(location, this);
            if (resource != null) {
                return resource;
            }
        }

        // 资源路径以"/"开头,表示是类路径上下文资源ClasspathContextResource
        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }
        // 资源以"classpath:"开头,表示是类路径资源ClasspathResource
        else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            // 否则认为是路径时URL,尝试作为URL解析
            try {
                // Try to parse the location as a URL...
                URL url = new URL(location);
                return new UrlResource(url);
            }
            catch (MalformedURLException ex) {
                // 如果不是URL,则再次作为类路径上下文资源ClasspathContextResource
                // No URL -> resolve as resource path.
                return getResourceByPath(location);
            }
        }
    }


    protected Resource getResourceByPath(String path) {
        return new ClassPathContextResource(path, getClassLoader());
    }
}

Note:
DefaultResourceLoader实现整体比较简单,但是值得借鉴的是使用ProtocolResolver扩展机制,可以认为是预留钩子。
所有ApplicationContext都继承了ResourceLoader接口从而具有了资源加载的基本能力,但是对于ApplicationContext都去主动实现该接口无疑使ApplicationContext强耦合资源加载能力,不易加载能力的扩展。Spring这里的设计非常精妙,遵循接口隔离原则。资源加载能力单独隔离成ResourceLoader接口,使其独立演变。ApplicationContext通过继承该接口而具有资源加载能力,ApplicationContext的实现中再继承或者组合ResourceLoader的实现DefaultResourceLoader。这样ResourceLoader可以自由扩展,而不影响ApplicationContext。当然Spring这里采用了AbstractApplicationContext继承DefaultResourceLoader。

Tips:
ResourceLoader虽然在Spring框架大量应用,但是ResourceLoader可以作为工具使用,可以极大简化代码。强力推荐应用中加载资源时使用ResourceLoader,应用可以通过继承ResouceLoaderAware接口或者@Autowired注入ResouceLoader。当然也可以通过ApplicationContextAware获取ApplicationContext作为ResouceLoader使用,但是如此,无疑扩大接口范围,有违封装性。详细参考:https://docs.spring.io/spring/docs/4.3.20.RELEASE/spring-framework-reference/htmlsingle/#resources

Spring另外一种资源加载方式ResourcePatternResolver是Spring中资源加载的核心。ResourcePatternResolver本身也是ResourceLoader的接口扩张。其特点:

  • 支持解析复杂化的资源路径
  • 加载多资源
public interface ResourcePatternResolver extends ResourceLoader {

    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    Resource[] getResources(String locationPattern) throws IOException;
}

getResources的定义决定了ResourcePatternResolver具有根据资源路径模式locationPattern加载多资源的能力。
并且提供了新的模式:在所有的类路径上"classpath*:"。

Note:
这里又使用到了策略模式,ResourcePatternResolver是策略接口,可以根据不同的路径模式封装实现相应的实现。有没有感觉到策略模式无处不在!

顶层上下文容器ApplicationContext通过继承ResourcePatternResolver使其具有按照模式解析加载资源的能力。这里不再赘述,前文接受ResourceLoader时有所描述。

ResourcePatternResolver的路径模式非常多,首先这是不确定的。根据不同的模式,有相应的实现。PathMatchingResourcePatternResolver是其标准实现。
在深入PathMatchingResourcePatternResolver的源码前,先了解下Ant—Style,因为PathMatchingResourcePatternResolver是ResourcePatternResolver在支持Ant-Style模式和classpath*模式的实现:

  1. "*"代表一个或者多个字符,如模式beans-*.xml可以匹配beans-xxy.xml;
  2. "?"代表单个字符,如模式beans-?.xml可以匹配beans-1.xml;
  3. "**"代表任意路径,如模式/**/bak.txt可以匹配/xxx/yyy/bak.txt;

在Spring中有Ant-Sytle匹配器AntPathMatcher。该匹配实现接口PathMatcher:

public interface PathMatcher {

	 // 判断给定模式路径是否为指定模式
    boolean isPattern(String path);

   	 // 判断指定模式是否能匹配指定路径path
    boolean match(String pattern, String path);
}

PathMatcher是一个策略接口,表示路径匹配器,有默认Ant-Style匹配器实现AntPathMatcher。

Note:
这里仍然使用策略模式。组合是使用策略模式的前提!

再回到PathMatchingResourcePatternResolver,其支持:

  • 解析Ant-Style路径;
  • 解析classpath*模式路径;
  • 解析classpath*和Ant-Style结合的路径;
  • 加载以上解析出来的路径上的资源;

PathMatchingResourcePatternResolver中持有AntPathMatcher实现对Ant-Style的解析,持有ResourceLoader实现对classpath*的解析。PathMatchingResourcePatternResolver中成员持有关系:

public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
    // 持有resouceLoader
    private final ResourceLoader resourceLoader;
    // 持有AntPathMatcher
    private PathMatcher pathMatcher = new AntPathMatcher();

    public PathMatchingResourcePatternResolver() {
        this.resourceLoader = new DefaultResourceLoader();
    }
    // 指定ResourceLoader构造
    public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
        Assert.notNull(resourceLoader, "ResourceLoader must not be null");
        this.resourceLoader = resourceLoader;
    }
}

在PathMatchingResourcePatternResolver中核心的方法数ResourcePatternResolver中定义的getResources的实现,其负责加载多样模式路径上的资源:

@Override
public Resource[] getResources(String locationPattern) throws IOException {
    Assert.notNull(locationPattern, "Location pattern must not be null");
    // 1.路径模式是否以classpath*开头
    if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
        // 路径模式是否为指定模式,这里指定模式是Ant-Style,即判断路径模式是否为Ant-Style
        // a class path resource (multiple resources for same name possible)
        if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
            // a class path resource pattern
            // 1-1.如果是Ant-Style,则在所有的类路径上查找匹配该模式的资源
            return findPathMatchingResources(locationPattern);
        }
        else {
            // 1-2.如果不是Ant-Style,则在所有类路径上查找精确匹配该名称的的资源
            // all class path resources with the given name
            return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
        }
    }
    // 2.不是以classpath*开头
    else {
        // Generally only look for a pattern after a prefix here,
        // and on Tomcat only after the "*/" separator for its "war:" protocol.
        // tomcat的war协议比较特殊,路径模式在war协议的*/后面,需要截取*/的路径模式
        int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
                locationPattern.indexOf(':') + 1);
        // 判断路径模式是否为指定的模式,这里是Ant-Style,即判断路径模式是否为Ant-Style
        if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
            // a file pattern
            // 2-1.是指定的路径模式,根据模式查找匹配的资源
            return findPathMatchingResources(locationPattern);
        }
        // 2-2.如果不是Ant-Style,则认为是单个资源路径,使用ResourceLoader加载单个资源
        else {
            // a single resource with the given name
            return new Resource[] {getResourceLoader().getResource(locationPattern)};
        }
    }
}

这里加载资源的逻辑根据路径模式的不同,分支情况非常多,逻辑也非常复杂。为了更加详细而清晰的探索,这里分别深入每种情况,并为每种情况举例相应的资源路径模式。

1.1-1分支(类路径资源模式)

1-1分支进入条件需要满足:

  • 路径以classpath*:开头;
  • 路径时Ant-Style风格,即路径中包含通配符;

如:classpath*:/META-INF/bean-*.xml和classpath*

spring源码系列—beandefinition扩展点

...精深,还有很多盲点需要摸索。整合前面的系列文章,从Resource到BeanDefinition,再到容器扩展点,最后到Bean创键,这个过程中无处不存在Spring预留的扩展口。本篇文章介绍Spring的另一种扩展点:BeanDefinition扩展点,该扩展点是为... 查看详情

spring源码系列——envoriment组件

何为EnvorimentEnvoriment是集成在Spring上下文容器中的核心组件,在Spring源码中由Envoriment接口抽象。在Environment中,有两大主要概念:Profile:在Spring中profile是针对Bean定义而言,是Bean定义的逻辑分组。通常表现为:dev/test/production等... 查看详情

spring读源码系列01---spring核心类及关联性介绍(代码片段)

Spring读源码系列01---Spring核心类及关联性介绍Spring核心类引子DefaultListableBeanFactoryDefaultListableBeanFactory的继承体系XmlBeanDefinitionReader容器的基础XmlBeanFactory配置文件--->Resource进入源码追踪XmlBeanFactory的构造函数loadBeanDefinit 查看详情

spring源码解析之resource

最近准备把spring,springmvc,mybtais,springboot,部分的cloud组件的源码重头梳理一下,并在语雀记录一下。Spring源码解析之Resource(一):https://www.yuque.com/dalianpai/spring/wlingm 查看详情

spring读源码系列之aop--02---aop基本概念扫盲---下

Spring读源码系列之AOP--02---aop基本概念扫盲---下引子AdvisorPointcutAdvisor:和切点有关的AdvisorAbstractPointcutAdvisor:抽象实现---可设置优先级AbstractGenericPointcutAdvisor一般的、通用的PointcutAdvisor---可配置adviceDefaultPoint 查看详情

spring读源码系列番外篇---02---propertyresolver的结构体系剖析---上(代码片段)

Spring读源码系列番外篇---02---PropertyResolver的结构体系剖析---上属性解析PropertyResolver---屏蔽不同底层属性源的获取属性接口的不同ConfigurablePropertyResolver---屏蔽不同底层属性源的获取属性接口的不同AbstractPropertyResolver---用于针对任... 查看详情

spring源码分析@autowire注入补充,@resource源码分析

自动注入补充的点:1:AutowireMode之前博客中讲到@Autowire,@Value,@Inject自动注入的处理都是在后置处理器 AutowiredAnnotationBeanPostProcessor#postProcessProperties中,这个后置处理器的调用是在 AbstractAutowireCapableBeanFactory#populateBean 查看详情

spring源码分析:resource资源定位一

最近回过头来,再次看spring源码,以前很多次都是随意的一看,但是有了以前的基础现在理解起来容易很多了,于是这次想要分析源码的过程中,想要始终带着几个疑问去看源码1.spring源码这样写的好处?2... 查看详情

spring-ioc源码解读2.1-beandefinition的resource定位

Spring通过ResourceLoader来处理得到的Resource。我们先看下前面提到的ClassPathXmlApplicationContext类定义:publicclassClassPathXmlApplicationContextextendsAbstractXmlApplicationContext{privateResource[]configResources;publicCl 查看详情

设计模式系列---简单工厂工厂方法抽象工厂

前言,最近看spring的源代码。发现之前没有完全弄懂(工厂方法、抽象工厂)的区别。spring中代理对象的产生,是通过代理工厂(工厂模式),首先spring中的代理是使用jdk或者cglib的代理,只要看目标类是否实现接口。publicclassPr... 查看详情

初识spring源码--initializebean|@postconstruct|afterpropertiesset|@resource(代码片段)

0.栗子:4.1initializeBean: 4.1.invokeAwareMethods: 4.2.applyBeanPostProcessorsBeforeInitialization: 4.3.invokeInitMethods: 4.4.applyBeanPostProcessorsAfterInitializatio 查看详情

初识spring源码--initializebean|@postconstruct|afterpropertiesset|@resource(代码片段)

0.栗子:4.1initializeBean: 4.1.invokeAwareMethods: 4.2.applyBeanPostProcessorsBeforeInitialization: 4.3.invokeInitMethods: 4.4.applyBeanPostProcessorsAfterInitializatio 查看详情

spring系列目录

Spring(https://spring.io/)系列目录第一篇:Spring系列一、Spring应用二、Spring源码分析三、Spring注意事项第二篇:SpringBoot系列一、SpringBoot应用二、SpringBoot源码分析三、SpringBoot注意事项第三篇:SpringCloud系列一、SpringCloud应用二、SpringCl... 查看详情

spring文档阅读之resources

ResourcesSpring定义用于处理位于classpath和相对路径下的资源的一系列接口方法。TheResourceInterfaceBuilt-inResourceImplementationsTheResourceLoaderTheResourceLoaderAwareinterfaceResourcesasDependencies1.1.TheResourceInterfaceSpri 查看详情

spring读源码系列06----容器扩展功能--上

Spring读源码系列06----容器扩展功能---上ApplicationContextClassPathXmlApplicationContext构造函数AbstractRefreshableConfigApplicationContext#setConfigLocations---设置配置文件路径AbstractApplicationContext#refresh---刷新容器Abstrac 查看详情

spring读源码系列07----容器扩展功能--中

Spring读源码系列07----容器扩展功能--中添加ApplicationContextAwareProcessor处理器initializeBean方法回顾(bean初始化过程)invokeAwareMethodsapplyBeanPostProcessorsBeforeInitializationinvokeInitMethodsapplyBeanPostProcessorsAfterIn 查看详情

spring源码系列——spring循环引用

众所周知spring在默认单例的情况下是支持循环引用的Appconfig.java类的代码@Configurable@ComponentScan("com.shadow")publicclassAppconfig{}1234X.java类的代码packagecom.shadow.service;importorg.springframework.beans.factory.annotation.A 查看详情

spring读源码系列08----容器扩展功能--下

Spring读源码系列08----容器扩展功能--下注册BeanPostProcessorregisterBeanPostProcessorsPostProcessorRegistrationDelegate#registerBeanPostProcessors初始化消息资源initMessageSourceMessageSource在哪里被使用呢?初始化ApplicationEve 查看详情