我们在学习Spring源码时都会感叹一句:尼玛,这么多类,看着看着这绕晕了.然后看着看着就看不下去了,累觉不爱啊再见再见,但是想想自己可怜的薪水,不学习如何升职加薪,迎娶白富美呢?所以硬着头皮把Spring源码看完。看完之后发现好像又都忘了大哭大哭不由感叹一番,程序猿真他妈累。为了不让大家重蹈我的覆辙,今天我带大家一起一步一步来实现一个Spring框架(说实现,感觉太厚脸皮了,其实就是把核心代码抽取出来,方便大家阅读)
首先让我们首先来了解一下IOC是个啥东西,官方上说是控制反转,那控制反转又是啥意思呢?就是创建对象的任务交给框架,晕,像我这种单身程序猿每天最大的乐趣就是new Object了,这点权利都要剥夺了。为啥要交给框架呢,就是为了低耦合,框架负责创建对象,也就是说人啊不能花心,乱搞对象,对象太多了关系就容易乱了。
我们把创建对象看做找女朋友,找到女朋友的第一步是得知道女朋友在哪里吧?深圳还是上海还是北京啊。Spring框架创建对象也是首先需要知道对象在什么位置。Spring通过Resource来定位文件的。比如我在D盘上放了一个苍老师的对象 D:\canglaoshi.xml
InputStream in = FileSystemResource(D:\canglaoshi.xml)
噢耶,我们成功跨出第一步:定位到目标了。这么容易啊,一句话的事就搞定了,其实得感谢Spring同志,它就相当于婚姻中介所,帮你搭桥牵线。我们来看看Spring同志如何帮我们完成的
public interface InputStreamSource {
public InputStream getInputStream() throws IOException;// 直接返回一个InputStream
}
我们首先来看看Resouce。你可以把它当做对象资源,也就是备胎了。
public interface Resource {
boolean exists(); // 妹子是否存在
boolean isReadable();//这个对象能不能接近,也许人家是高冷女神,这个时候我们还是放弃吧,屌丝程序猿无法拿下的
boolean isOpen();// 是否名花有主了,Spring是不允许任何人挖墙脚的,毕竟这样是不道德的。
URL getURL() throws IOException;//就是告诉你妹子的地址,光有地址你不一定找得到,万一恰巧妹子不在呢
URI getURI() throws IOException;//把地址和电话号码一起都告诉你了,这样你就可以找的妹子咯
File getFile() throws IOException;//就是获得你硬盘的苍老师对象了,这个最简单了,相信大家都能找到
String getFilename();//妹子的名字
String getDescription();//妹子的身高,体重,三维信息了
}
AbstractResource代表一个抽象的资源,实现了一些公共的方法。看看下面的方法,心塞啊,看到abstract,你没有交费,想获得资源,门都没有。
public abstract class AbstractResource implements Resource {
/**
* 你电脑里有没有下载苍老师
*/
@Override
public boolean exists() {
try {
return getFile().exists();
}
catch(IOException ex) {
try {
InputStream is = getInputStream();
is.close();
return true;
}
catch (Throwable isEx) {
return false;
}
}
}
/**
* 一般妹子都会给你一个接近的机会的
*/
@Override
public boolean isReadable() {
return true;
}
/**
* 判断文件是否可以被打开,你还不是会员,当然不能打开
*/
@Override
public boolean isOpen() {
return false;
}
/**
* 我是不会告诉你地址的,除非你升级为FileSystemResource获取其他会员,你要是用强,我死给你看
*/
@Override
public URL getURL() throws IOException {
throw new FileNotFoundException(getDescription()+"cannot be resolved to URL");
}
/**
* 如果你能获得我的URL,我就给机会让你获得URI
*/
@Override
public URI getURI() throws IOException {
URL url = getURL();
try {
return ResourceUtils.toURI(url);
}
catch (URISyntaxException ex) {
throw new IOException("Invalid URI [" + url + "]", ex);
}
}
/**
* 嘿,别费心了,你找不到我的
*/
@Override
public File getFile() throws IOException {
throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
}
/**
* 我不是一个随便的人,我的名字你休想知道
*/
@Override
public String getFilename() {
return null;
}
@Override
public String toString() {
return getDescription();
}
@Override
public boolean equals(Object obj) {
return (obj == this ||
(obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));
}
@Override
public int hashCode() {
return getDescription().hashCode();
}
要找到对象,还是得升级会员,每人交10块钱,先来一个初级会员FileSystemResource吧
public class FileSystemResource extends AbstractResource implements WritableResource{
private final File file;// 这就是仓老师了,交了10块钱,终于见到了你
private final String path;// 仓老师的地址
/**
*通过File,桌面快捷方式,就可以找到苍老师的资源了
*/
public FileSystemResource(File file) {
this.file = file;
this.path = file.getPath();
}
/**
*通过路径,比如D:\canglaoshi,就可以找到苍老师的资源了
*/
public FileSystemResource(String path) {
this.file = new File(path);
this.path = path;
}
/**
*通过File就可以获得URL了
*/
@Override
public URL getURL() throws IOException {
return this.file.toURI().toURL();
}
@Override
public URI getURI() throws IOException {
return this.file.toURI();
}
@Override
public File getFile() throws IOException {
return this.file;
}
public final String getPath() {
return this.path;
}
@Override
public boolean exists() {
return this.file.exists();
}
@Override
public boolean isReadable() {
return (this.file.canRead() && !this.file.isDirectory());
}
@Override
public InputStream getInputStream() throws IOException {
return new FileInputStream(this.file);
}
@Override
public boolean isWritable() {
return (this.file.canWrite() && !this.file.isDirectory());
}
@Override
public OutputStream getOutputStream() throws IOException {
return new FileOutputStream(this.file);
}
@Override
public String getDescription() {
return "file [" + this.file.getAbsolutePath() + "]";
}
@Override
public boolean equals(Object obj) {
return (obj == this ||
(obj instanceof FileSystemResource && this.path.equals(((FileSystemResource) obj).path)));
}
@Override
public int hashCode() {
return this.path.hashCode();
}
}
升级为初级会员真好,所有的信息都可以获得了,等下,看看AbstractResource 实现了WritableResource,这是一个什么东东??
public interface WritableResource extends Resource {
/**
*是否可以改造妹子
*/
boolean isWritable();
/**
* 获得改造妹子的工具OutputStream
*/
OutputStream getOutputStream() throws IOException;
}
Spring兄真好,还提供这种特殊服务,但是想想还是先算了,我们一般不会有机会改造妹子的,找到了都算不错了,还改造,小心以后妹子直接甩了你。