ClassPathResource详解ClassPathResource详解
ClassPathReource resource=new ClassPathResource("l");
1: public class ClassPathResource extends AbstractFileResolvingResource
在ClassPathResource中,含参数String path的构造函数:
public ClassPathResource(String path ) {
this ( path , (ClassLoader) null);
}
2:上述构造函数指向了另外⼀个构造函数:
public ClassPathResource (String path , ClassLoader classLoader ) {
Asrt. notNull( path, "Path must not be null");
String pathToU = StringUtils. cleanPath( path);
if ( pathToU .startsWith( "/")) {
pathToU = pathToU .substring(1);
}
this . path = pathToU;
this . classLoader = ( classLoader != null ? classLoader : ClassUtils. getDefaultClassLoader()); }
能够看到path由StringUtils的cleanPath⽅法返回了pathToU。由此,我们找到StringUtils的cleanPath⽅法3: public abstract class StringUtils
public static String cleanPath (String path ) {
if ( path == null) {
return null ;
}
String pathToU = replace( path , WINDOWS_FOLDER_SEPARATOR , FOLDER_SEPARATOR);
int prefixIndex = pathToU .indexOf( ":" );
String prefix = "" ;
if ( prefixIndex != -1) {
prefix = pathToU .substring(0, prefixIndex + 1);
pathToU = pathToU .substring( prefixIndex + 1);
}
if ( pathToU .startsWith( FOLDER_SEPARATOR)) {
prefix = prefix + FOLDER_SEPARATOR;
pathToU = pathToU .substring(1);
}
String[] pathArray = delimitedListToStringArray( pathToU, FOLDER_SEPARATOR );
List<String> pathElements = new LinkedList<String>();
int tops = 0;
for ( int i = pathArray. length - 1; i >= 0; i --) {
String element = pathArray [ i ];
if ( CURRENT_PATH .equals( element)) {
// Points to current directory - drop it.
}
el if ( TOP_PATH.equals( element)) {
// Registering top path found.
tops ++;
}
el {机智的近义词
if ( tops > 0) {
// Merging path element with element corresponding to top path.
tops --;
}
el {
// Normal path element found.
pathElements .add(0, element );
}
}
}
/
角球是什么意思/ Remaining top paths need to be retained.
for ( int i = 0; i < tops; i++) {
pathElements .add(0, TOP_PATH);
}
return prefix + collectionToDelimitedString( pathElements, FOLDER_SEPARATOR );
}
4:StringUtils类中 replace⽅法
public static String replace (String inString , String oldPattern , String newPattern ) {
if (! hasLength( inString ) || ! hasLength( oldPattern) || newPattern == null ) {
return inString ;
}
StringBuilder sb = new StringBuilder();
int pos = 0; // our position in the old string
int index = inString .indexOf( oldPattern );
// the index of an occurrence we've found, or -1
int patLen = oldPattern.length();
while ( index >= 0) {
sb.append( inString .substring( pos , index ));
sb.append( newPattern );
pos = index + patLen;
index = inString .indexOf( oldPattern, pos );
}
sb.append( inString .substring( pos ));
// remember to append any characters to the right of a match
return sb .toString();
}
5:StringUtils类类中的hasLength⽅法。由此可以看出,同样的⽅法名,不同的⽅法签名,然后在其中⼀个⽅法中引⽤另外⼀个⽅法。好多类都是这么⽤的,就像开始的时候的构造函数那样,虽然不知道好处 是什么,但先记下来。
public static boolean hasLength (String str) {
return hasLength((CharSequence)str);
}
public static boolean hasLength (CharSequence str) {
return(str!=null&&str.length() > 0);
}
跟踪到这⾥,可以知道hasLength⽅法的⽬的就是str不为空且str的长度⼤于0。突然发现CharSequence这个类没接触过,来看⼀下它的源码
6: public interface CharSequence{}
额,源码没看懂就不粘贴过来了。
7:回到StringUtils的replace⽅法眼睛的颜色
⾸先判断传⼊的三个参数,如果为空后者长度⼩于0,直接返回inString;那么我看⼀下这三个参数都是什么:
inString :path 这个就是我们传⼊的⽂件名
oldPattern: private static final String WINDOWS_FOLDER_SEPARATOR="\\";
newPattern: private static final String FOLDER_SEPARATOR="/";这两个是⽂件分隔符
然后给局部变量index赋值,通过查阅API:
public int indexOf(int ch)
返回指定字符在此字符串中第⼀次出现处的索引。
意思就是在path中查找"\\",例如我写⽂件的绝对路径是D:\\⽂件\\API\\JDK_API_1_6_zh_CN.CHM,我就需要循环的读取“\\”,接下来while循环中出现了substring⽅法,继续查阅API:
public substring(int beginIndex)
返回⼀个新的字符串,它是此字符串的⼀个⼦字符串。该⼦字符串从指定索引处的字符开始,直到此字符串末尾。
public substring(int beginIndex,
int endIndex)
返回⼀个新字符串,它是此字符串的⼀个⼦字符串。该⼦字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该⼦字符串的长度为 endIndex-beginIndex
故此 ,第⼀次循环会把path路径中从0索引开始,直到第⼀个"\\"之间的内容添加到StringBuffer中,然后再在StringBuffer中添
加“/”,接下来pos和index都需要改变,要往后挪。因为循环需要往后⾛,我们要找到第⼆个“\\”,觉得这个有点算法的意思。返回
总结⼀下replace⽅法,本意是根据传⼊的路径path,如果是D:\\⽂件\\API\\JDK_API_1_6_zh_CN.CHM这种格式的,给转换成D:/⽂
件/API/JDK_API_1_6_zh_CN.CHM这种格式。
8:StringUtils的cleanPath⽅法:
通过replace的返回值,我们得到了可以⽤的路径pathToU,然后我们要把这个路径下“:”给找出来,正如代码
int prefixIndex=pathToU.indexOf(":");
那样,需要知道,indexOf⽅法只要没找到相应的字符,就会返回-1,所以在下⾯的判断中才会以perfixIndex是否为-1来进⾏判断。如果路 径中有“:”,接着以D:/⽂件/API/JDK_API_1_6_zh_CN.CHM举例,prefix="D:" pathToU="/⽂
件/API/JDK_API_1_6_zh_CN.CHM ",这个很有意思,因为程序不知道我们输⼊的是绝对路径 带D:的这种 ,还是/开头的这种,或者说相对路径,程序直接全给你判断了。接下来会判断pathToU是否以“/"开头,是的话prefix会加上“/”,现在的prefix有两种情况,可能是"D:/"这种,也可能是"/"这种,⽽pathToU肯定是“⽂件/API/JDK_API_1_6_zh_CN.CHM ”这种了。
String[]pathArray= delimitedListToStringArray(pathToU,FOLDER_SEPARATOR);
看到这句代码,我估计是把pathToU给拆成字符串数组⾥,就像是这样,⽂件 API ***的这种。接下来看看具体的代码是不是这样:
9:StringUtils的delimitedListToStringArray⽅法
public static String[] delimitedListToStringArray(String str, String delimiter) {
return delimitedListToStringArray(str,delimiter,null);
ie浏览器怎么升级
}
public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {
if(str==null) {
return new String[0];
}
if(delimiter==null) {
return new String[] {str};
}
List<String>result=new ArrayList<String>();
if("".equals(delimiter)) {
for(int i= 0;i<str.length();i++) {
result.add(deleteAny(str.substring(i,i+ 1),charsToDelete));
}
}
el{
int pos= 0;
int delPos;
while((delPos=str.indexOf(delimiter,pos)) != -1) {
result.add(deleteAny(str.substring(pos,delPos),charsToDelete));
pos=delPos+delimiter.length();
}
if(str.length() > 0 &&pos<=str.length()) {
// Add rest of String, but not in ca of empty input.
result.add(deleteAny(str.substring(pos),charsToDelete));
}
}
return toStringArray(result);
}
先看看传⼊的参数:
str:pathToU,就是⽂件/API/JDK_API_1_6_zh_CN.CHM
delimiter:"/"
charsToDelete:null
public static String deleteAny(String inString, String charsToDelete) {
if(!hasLength(inString) || !hasLength(charsToDelete)) {
return inString;
}
StringBuilder sb=new StringBuilder();
for(int i= 0;i<inString.length();i++) {
char c=inString.charAt(i);
if(charsToDelete.indexOf(c) == -1) {
sb.append(c);
}
}
庖丁解牛原文
String();
}
如果说我们传⼊的"/"等于""的话,显然是不可能,我们所假如的话,会把pathTOU倒着循环,每个字符都摘出来,然后当成字符串⽤,传⼊deleteAny中,然后⼜是循环,对每个字符⽽⾔,如果charsToDelete中没有这个字符,就在StringBuilder中添加这个字符。返回值是String。当然了,这个
还没⽤到。我们⽤到的是那个很复杂的el
我们遇到了⼀个循环,对pathToU⽽⾔,从索引0开始,如果pathToU中有"/",就像⽂件/API/JDK_API_1_6_zh_CN.CHM 我们会得到“⽂件,然后还会进⼊deleteAny这个⽅法,参数inString就是"⽂件",charsToDelete是null,突然发现charsToDelete的值为Null的话会直接返回InString,也就是“⽂件”。返回到 delimitedListToStringArray⽅法之后,接着往后循环,最终的结果就是实现了把pathToU 给切割成若⼲个String的形式。
10:回到StringUtils的cleanPath⽅法
我们遇到了⼀个倒着的循环,如果说我们这个是特别正常的路径,就相当于复制了,如果是以.或者..结尾的这些内容,我们就把它给忽略了。
购房合同书我得承认上⾯这些过程真的好复杂,其实就是做了⼀件事,对输⼊的路径进⾏了处理,只不过考虑的情况多了⼀点。所以我决定还是⽤debug来⾛⼀遍看看。
这时我⽤的是绝对路径
终于熬到了这个⽅法的结束。
11:回到ClassPathResource的构造函数
this.classLoader= (classLoader!=null?classLoader: DefaultClassLoader());
如果传⼊的classLoar有值,就返回这个值,如果没有,就获取⼀个。
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl=null;
try{
cl= Thread.currentThread().getContextClassLoader();
}
catch(Throwable ex) {
建筑工程施工技术// Cannot access thread context ClassLoader -
}
if(cl==null) {
/
/ No thread context class loader -> u class loader of this class.
cl= ClassLoader();
if(cl==null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try{
cl= SystemClassLoader();
}
catch(Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live
}
}
}
return cl;
}
写到这,我们的ClassPathResouce resouce实例就有了path 和 classLoader这两个关键属性。
如果我们想获取输⼊流
@Override
public InputStream getInputStream()throws IOException {
InputStream is;
if(this.clazz!=null) {
is=ResourceAsStream(this.path);
}
el if(this.classLoader!=null) {
is=ResourceAsStream(this.path);
}
el{
is= SystemResourceAsStream(this.path);
}
白蛇传故事
if(is==null) {
throw new FileNotFoundException(getDescription() +" cannot be opened becau it does not exist");
}
return is;
}
会判断clazz 有没有值,classLoader有没有值,然后再获取输⼊流。前两天整理了java.lang.Class这个类的意思,现在就能⽤⼀点了,先看看定义的⼀些属性
private final String path;
private ClassLoader classLoader;
private Class<?>clazz;
ClassPathResource有好⼏个构造函数,有的构造函数会传⼊classLoader,有的会传⼊clazz,这个clazz就是相应的类在JVM上的实例,显然上⾯的例⼦中并没有这个东西,⽽classLoader是有的,所以通过classLoader获取输⼊流。我觉得对ClassPathResource理解的更透彻了,虽然⼤部分时间都是在对path进⾏处理。近期还要看看ClassLoader,还不是很清楚它的⼯作机制。