本文是Spring中Resource的一个思考点。
前言
Resource、ResourceLoader、ResourcePatternResolver、容器的关系错综复杂,当简化到这种程度就比较容易看了。但是我还是在如何获取Resource上绕了一下。
一、一个疑问?
容器AbstractApplicationContext继承了ResourcePatternResolver,但同时有一个该类型的成员。其实例为PathMatchingResourcePatternResolver的实例。容器实现ResourcePatternResolver的getResources(String locationPattern)方法是调用PathMatchingResourcePatternResolver的实例的该方法实现的。
但是PathMatchingResourcePatternResolver的构造器是传入一个ResourceLoader来初始化的。AbstractApplicationContext实例化PathMatchingResourcePatternResolver的时候传入了自身this。而PathMatchingResourcePatternResolver又是调用ResourceLoader(也就是AbstractApplicationContext)的getResource(String location)来获取Resource。
感觉无解啊。。(大佬勿喷。)
二、直接说原因
因为AbstractApplicationContext继承自DefaultResourceLoader。DefaultResourceLoader实现了ResourceLoader,这里就有getResource(String location)的实现。
三、如果还没理解
我举个例子,如下图所示。
1.接口People和实现类DefaultPeople
分别定义和实现了吃饭这个功能。
public interface People {
public void eat();
}
public class DefaultPeople implements People {
@Override
public void eat() {
System.out.println("我能吃饭");
}
}
2.接口Grandpa、Parent1和父类Parent2
Grandpa是People的子接口。
Parent1是Grandpa的子接口。
Parent2是Grandpa的实现类。
public interface Grandpa extends People{ }
public interface Parent1 extends Grandpa { }
public class Parent2 implements Grandpa {
Grandpa grandpa;
public Parent2(Grandpa grandpa){
this.grandpa = grandpa;
}
@Override
public void eat() {
grandpa.eat();
}
}
3.Son子类
继承自DefaultPeople,实现了Parent1接口。
public class Son extends DefaultPeople implements Parent1 {
Grandpa grandpa;
public Son(){
grandpa = getGrandPa();
}
private Grandpa getGrandPa() {
return new Parent2(this);
}
public static void main(String[] args) {
Son son = new Son();
son.grandpa.eat();
}
}
逻辑就清楚了吧,son要eat,首先构造了一个Grandpa 的子类Parent2的实例,并把自己传给了他。
eat要调用Parent2的eat方法。但是Parent2的eat方法也是调用传入者自己的eat方法。那么最后调用的谁的eat方法。当然是Son类的eat方法。因为Son继承了DefaultPeople ,是这4个人里唯一有实现的地方。