spring学习5(1)
在经过了对spring框架基本开发的了解以及对spring boot流程的学习,《精通spring4.x…》这本书正式开始了spring的讲解,我也跟随着这本书的脚步进行学习。
IoC概述
首先需要学习的是spring的IoC技术,IoC全称是Inverse of Control,是spring容器的内核。
IoC的基本意义
即是将一个接口具体实现类的控制权从调用的类中移除,交给第三方来控制。如果从电影剧本的角度即是说,演员,剧本,角色的对应由导演来控制。在spring中就是spring容器借用Bean配置来进行控制。
后来由于这个概念不够直观引入了DI(Dependency Injection)依赖注入的概念,即是说调用类对某一接口实现类的依赖关系由第三方注入。
IoC的类型
IoC可以划分为三种类型:构造函数注入,属性注入,接口注入。Spring支持构造函数注入和属性注入。
构造函数注入
通过调用类的构造函数,将接口类通过构造函数给出。
用电影的例子就是,导演分配角色的演员,而后在剧本的构造函数中将这个演员注入。
属性注入
通过调用类的函数,将接口类通过函数给出。
用电影的例子就是不是这个角色在所有的场景都需要,所以这时候可以通过setter方法来注入演员。
接口注入
将调用类所有依赖注入的方法抽取到一个接口中,调用类通过实现该接口的注入方法来达成注入。
通过容器完成依赖关系的注入
虽然如同上述一般操作后,调用类之间完成了解耦,然而这些代码在第三个类中依然存在。就好像导演要控制其他两个类,如果这时候有个第三方的代理机构只是让导演,剧本,演员各司其职,那么三个类都完成了解耦。那么spring就是这样一个容器,通过new XmlBeanFactory)
就可以启动容器并且完成装配。
JAVA反射机制
java语序通过程序化的方式间接对Class进行操作。
概念
可以通过一例子来说明。通常我们要实现一个类并赋予初值可以使用构造函数直接赋值,或是创建后用setter方法来赋值,这就属于直接调用目标类。
于此相对,我们可以创建一个ClassLoader用来获取当前线程,而后通过指定的全限定类名来装载目标类的反射实例。之后我们就可以利用反射类的各个对象来操作类,从而达到创建等方法的实现的目标。
类装载器ClassLoader
定义和工作流程
类装载器就是寻找类的节码文件并构造出类在jvm内部表示对象的组件。其经历以下步骤把一个类装入jvm:
- 装载:查找和导入Class文件
- 链接:
- 校验:检查载入Class文件数据的正确性
- 准备:给类的静态变量分配存储空间
- 解析:将符号引用转换成直接引用
- 初始化:对类的静态变量,静态代码块执行初始化工作。
构成
JVM在运行时会有三个ClassLoader,其中他们有父子关系:
- 根装载器:使用c++编写,在java中不可见,不是ClassLoader的子类,负责装载jre的核心库类。
- ExtClassLoader:是根装载器的子类,负责装载jre扩展目录ext中的jar类包。
- AppClassLoader:是ExtClassLoader的子类,负责装载classpath路径下的类包,默认使用该类装载应用程序的类。
全盘负责委托机制
JVM有全盘负责委托机制,是指当一个ClassLoader载入一个类时,其所依赖和引用的类也由同一个ClassLoader载入;先委托父装载器寻找目标类,只有找不到才从自己的路径中查找并转载目标类。
这个机制也是导致NoSUchMethodError问题的原因,如果在类路径有多个不同版本的类包就有可能导致错误。
反射机制
即是可以从Class对象中获取构造函数,成员变量方法类等反射对象即是包括了private或protected成员变量和方法的但是要申明setAccessible(boolean access)
。
主要有:
- 类的构造函数反射类(Constructor):通过getConstructors(parameterType)方法(或getDeclaredConstructors(parameterType))获取拥有特定入参的构造函数反射对象,并且可以通过newInstance来实例化。
- 类方法的反射类:通过getMethods()来获得特定的方法反射类,其最主要的方法是invoke(Object obj, Object[] args)来调用原方法。
- 类的成员变量反射类:通过getDeclaredFields(String name)方法来获取特定的成员变量反射类,可以通过set(Object obj, Object value)来使用。
实例如下:
package com.smart.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
public class ReflectTest{
public static Car initByDefaultConst() throws Throwable{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("com.smart.reflect.Car");
Constructor cons = clazz.getDeclaredConstructor((Class[])null);
Car car = (Car)cons.newInstance();
Method setBrand = clazz.getMethod("setBrand", String.class);
setBrand.invoke(car, "XXX");
Method setColor = clazz.getDeclaredMethod("setColor", String.class);
setColor.invoke(car, "Dark");
Method setMaxSpeed = clazz.getDeclaredMethod("setMaxSpeed", int.class);
setMaxSpeed.invoke(car, 200);
return car;
}
public static void main(String[] args) throws Throwable{
Car car = initByDefaultConst();
car.introduce();
}
}
资源访问利器
资源抽象接口
jdk所提供的访问资源的类并不能很好地满足各种底层资源的访问需求,比如从类路径或web容器的上下文中获取资源的能力。
为此,Spring设计了一个Resource接口,它为应用提供了更强的底层资源访问能力。其主要方法如下:
bollean exists()
:资源是否存在
bollean isOpen()
:资源是否打开
URL getURL() throws IOException
:如果底层资源可以表示程URL,则该方法返回对应的URL对象。
FIle getFile() throws IOException
:如果底层资源对应一个文件则该方法返回对应的File对象。
InputStream getInputStream() throws IOException
:返回资源对应的输入流。
具体实现类
- WriteableResource:可写资源接口,有两个实现类:FileSystemResource和PathResource。
- ByteArrayResource:二进制数组表示的资源。
- ClassPathResource:类路径下的资源,资源以相对于类路径的方式表示。
- FileSystemResource:文件系统资源,资源用系统路径的方式表示如“D:/XXX/XXX.xml”等。
- InputStreamResource:以输入流返回表示的资源。
- ServletContextResource:为访问Web容器上下文的资源而设计的类,负责以相对于web应用根目录的路径加载资源,支持以流和URL的方式访问,在war解包的情况下,也可以通过File方式访问。
- URLResource:URL封装了java.net.URL可以访问任何通过URL表示的资源。
- PathResource:提供的读取资源文件的类,可以访问通过URL,Path,系统文件路径表示的资源。
在获取资源后,用户就可以通过Reaource接口定义的多个方法来访问文件其他信息,如getFileName()方法来获取文件名,通过getInputStream()方法来获取文件的输入流等。
注意在资源配置文件在项目发布时会被打包,所以不能使用getFile()方法了,而要用getInputSteam(),这个问题码一下。
资源加载
资源地址表达式
为了访问不同类型的资源,必须使用相应的Resource实现类,spring提供了强大的加载资源机制来简化了这一过程。仅通过资源地址的特殊标识就可以访问相应的资源,还支持ant风格的资源地址。
有如下较常见的地址前缀:
classpath:
/classpath:/
:这两个都是相对于类的根路径开始。资源文件可以在文件系统中也可以在jar或zip的类包中。特别注意classpath*:
可以扫描所有的同名包并加载所需。file:
:使用URLResource从文件系统目录中装载资源,可以是相对路径,也可以是绝对路径。http://
:使用UrlResource从web服务器中装载资源。ftp://
:使用UrlResource从ftp服务器中装载资源- 无前缀:根据ApplicationContext来具体决定。
ant
ant是一个允许通配符的格式
- ?:匹配文件名中的一个字符
- *:匹配文件名中的任意字符
- **:匹配多层路径
- 。。。
资源加载器
spring定义了一套资源加载的接口其关系如下:
PathMatchingResourcePatternResolver->
ResourcePatternResolver->
ResourceLoader->
Resource
这其中REsourceLoader接口是不支持ant的,但是ResourcePatternResolver扩展了其接口,而PathMathingResourcePatternResolver是spring的标准实现类,例子如下
package com.smart.resource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.testng.annotations.*;
import static org.testng.Assert.*;
public class PatternResolverTest{
@Test
public void getResources() throws Throwable{
ResourcePatternResolver resolver =
new PathMatchingResourcePatternResolver();
Resource resources[] = resolver.getResources("classpath*:com/smart/**/*.xml");
assertNotNull(resources);
for(Resource resource:resources) {
System.out.println(resource.getDescription());
}
}
}