31、深入解析spring技术$1
通过前面30章的学习,应该对java的基础及一些jvm底层有了初步了解,接来下将要剖析java最为成功的框架spring;通过剖析整个过程将帮助我们了解jvm底层运作和代码设计风格;
先来认识一下spring的缔造者:Rod Johnson; 搞音乐出生的,长的还有点丑,他提出了一个理念:不要滥造车*;意思是做车*很简单,现在已经有了比较优秀的js封装库像jQuery、nodejs等,而有些三流软件公司放着不用,偏要自己开发一套封装库,让不懂js的人以为这家公司很nb;这句话的另外一个意思:就是造*就要造出足够优秀的*;
他写了几本书:《Expert One-on-One J2EE Design and Development》spring核心思想,他的英文比较烂,一般人不知道他要说什么,估计还没人能翻译成能读的中文;《expert one-on-one J2EE Development without EJB》写了一本书在说EJB的坏话;《Professional Java Development with the spring framework》一看书名就是在给spring做广告;
spring有多优秀,那是一个关于春天的故事!
what you will learn from this book?《Professional Java Development with the spring framework》
1、The core inversion of control container(容器) and the concept(概念) of dependency injection(注入); IoC容器
2、Spring's aspect oriented(面向、定向) programming framework and why aop is important in j2ee development; AoP框架
3、How to use spring's programmatic(框架) and declarative transaction management services effectively;
4、how to access data using spring's JDBC functionality?
5、Spring services for accessing and implementing EJBs; spring为EJB提供访问和实现功能
6、Spring's remoting(扩展ing) framework;
spring官网:http://spring.io/
先来熟悉几个概念:
1、控制反转:原先一个类A{private String name;} 的属性name需要在实例中为其赋值;比如skx.setName(“skx”);完成这个赋值过程是由 具体的对象实例 完成的;现在就是把这种赋值的权限交给IoC容器,由IoC为实例的属性赋值;比如<bean id="skx" class="org.spring.A"><property name="name" value="skx"/></bean>就完成了对实例属性的赋值;
2、紧耦合: 比如 A{private B b;}这里A就依赖于属性b,如果属性b的属性和方法发生了变化,极有可能影响到a的功能实现;
接口解耦:看过25章设计模式之结构模式的外观模式,就会知道如何实现解耦;
3、设计模式的开闭原则:查看27章设计模式之6大原则的开闭原则;
spring3.1
在spring所有功能中,最基础最核心的莫过于IoC了,而IoC容器的具体实现类都是实现BeanFactory这基本接口:
public interface BeanFactory {
//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义
String FACTORY_BEAN_PREFIX = "&";
//这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。
Object getBean(String name) throws BeansException;
//这里根据bean的名字和Class类型来得到bean实例。
Object getBean(String name, Class requiredType) throws BeansException;
//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean
boolean containsBean(String name);
//这里根据bean名字得到bean实例,并同时判断这个bean是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//这里对得到bean实例的Class类型
Class getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);
}
一个Bean 的解析过程非常复杂,功能被分的很细,扩展了很多接口、抽象类和实现类,错综复杂、眼花缭乱,但是最终的实现类有:XmlBeanFactory,ClasspathXmlApplicationContext等等。
实箭头表示继承或实现父类或父接口,虚箭头表示依赖所指向的类或接口;
BeanFactory下的10个接口:
从上张图可以看出,ApplicationContext这个接口和最下面的三个接口应该是比较有用的接口;
下面来看下实现类的关系图:XmlBeanFactory主要接口是ConfigurableListableBeanFactory;黄框表示在前面的图中出现,不再向上追溯:
XmlBeanFactory声明过时了,来看下面4个现在比较常用的实现bean解析的类:
这张图中,AbstractApplicationContex、AbstractRefreshableConfigApplicationContextt和4个实现类比较重要;
在Spring中,所有的Bean都是有BeanFactory(IoC容器先可以理解为beans.xml)来进行管理的,在BeanFactory中设计了4个getBean方法,通过getBean来获得beans.xml文件中的bean,
返回类型:boolean 方法 :containsBean
返回类型:Object 方法 :getBean
返回类型:T 方法 :getBean
返回类型:T 方法 :getBean
返回类型:Object 方法 :getBean
返回类型:boolean 方法 :isSingleton
返回类型:boolean 方法 :isPrototype
返回类型:boolean 方法 :isTypeMatch
返回类型:Class<?> 方法 :getType
返回类型:String; 方法 :getAliases
返回类型:boolean 方法 :containsLocalBean
返回类型:BeanFactory 方法 :getParentBeanFactory //获得BeanFactory
$1、Resource接口
Spring中,对于资源文件采用一个接口Resource表示。其主要实现类有ClassPathResource、FileSystemResource、UrlResource、ByteArrayResource、ServletContextResource和InputStreamResource。
注:ClassPathContextResource是DefaultResourceLoader的内部类
Resource的主要方法:
- 返回类型:Resource 方法 :createRelative
- 返回类型:boolean 方法 :isReadable 用于判断对应资源的内容是否可读。需要注意的是当其结果为true的时候,其内容未必真的可读,但如果返回false,则其内容必定不可读。
- 返回类型:URI 方法 : getURI
- 返回类型:URL 方法 :getURL 返回当前资源对应的URL。如果当前资源不能解析为一个URL则会抛出异常。如ByteArrayResource就不能解析为一个URL。
- 返回类型:String 方法 :getFilename
- 返回类型:boolean 方法 :exists 用于判断对应的资源是否真的存在。
- 返回类型:boolean 方法 :isOpen 用于判断当前资源是否代表一个已打开的输入流,如果结果为true,则表示当前资源的输入流不可多次读取,而且在读取以后需要对它进行关闭,以防止内存泄露。该方法主要针对于InputStreamResource,实现类中只有它的返回结果为true,其他都为false。
- 返回类型:long 方法 :lastModified
- 返回类型:File 方法 :getFile 返回当前资源对应的File。如果当前资源不能以绝对路径解析为一个File则会抛出异常。如ByteArrayResource就不能解析为一个File。
- 返回类型:long 方法 :contentLength
- 返回类型:String 方法 :getDescription
ClassPathResource获取相对路径下的文件,new ClassPathResource(“test.txt”);
SystemResource可用来获取文件系统里面的资源。
UrlResource可用来代表URL对应的资源,它对URL做了一个简单的封装。通过给定一个URL地址,我们就能构建一个UrlResource。
ByteArrayResource是针对于字节数组封装的资源,它的构建需要一个字节数组。
ServletContextResource是针对于ServletContext封装的资源。
InputStreamResource是针对于输入流封装的资源,它的构建需要一个输入流。
getInputStream()是InputStreamSource的唯一声明的抽象方法,返回InputStream;
//将相对地址的 文本文件转为字符流
public InputStream readRelative(String filePath) throws IOException {
Resource resource = new ClassPathResource(filePath);
String fileName = resource.getFilename();
if (resource.isReadable()) {
InputStream is = resource.getInputStream();
return is;
}
return null;
}
//将绝对地址 的 文本文件转为字符流
public InputStream readAbsolutely(String filePath) throws IOException {
Resource resource = new FileSystemResource(filePath);
if (resource.isReadable()) {
InputStream is = resource.getInputStream();
return is;
}
return null;
}
//将URL地址内容转为字符流,注意转码,百度是utf-8
public InputStream readURL(String urlPath) throws IOException {
urlPath = urlPath.startsWith("http")?urlPath:("http://"+urlPath);
Resource resource = new UrlResource(urlPath);
if (resource.isReadable()) {
InputStream is = resource.getInputStream();
return is;
}
return null;
}
//将字节内容转为字符流
public InputStream readByte(byte[] b) throws IOException {
Resource resource = new ByteArrayResource(b);
if (resource.isReadable()) {
InputStream is = resource.getInputStream();
return is;
}
return null;
}
##########
//将字符型文件读出,返回一个字符串
public String read(String filename) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(filename));
String s;
StringBuffer sb = new StringBuffer();
while ((s = br.readLine()) != null) {
sb.append(s + "\n");
}
br.close();
return sb.toString();
}
//将字符输入流读出,返回一个字符串
public String read(InputStream is) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String s;
StringBuffer sb = new StringBuffer();
while ((s = br.readLine()) != null) {
sb.append(s + "\n");
}
br.close();
return sb.toString();
}
通过上面的几个方法,大致就可以将字符型文件定位,如果不是字符型的文件如何读取呢?参看IO文件复制
//将字节文件转换为字节数组
public byte[] readB(File file) throws IOException {
BufferedInputStream bf = new BufferedInputStream(new FileInputStream(file));
try {
byte[] data = new byte[bf.available()];
bf.read(data);
return data;
} finally {
bf.close();
}
}
//将字节文件转换为字节数组
public byte[] readB(String filePath) throws IOException {
return readB(new File(filePath));
}
字符流文件包括:txt、xml、html等
二进制文件:图片、音视频、doc、pdf 等