Spring学习5(1):IoC容器之IoC概述,JAVA反射机制,资源访问器

版权声明:本文real_Rickys原创文章,未经real_Rickys允许不得转载。 https://blog.csdn.net/real_Rickys/article/details/82966482

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:

  1. 装载:查找和导入Class文件
  2. 链接:
    1. 校验:检查载入Class文件数据的正确性
    2. 准备:给类的静态变量分配存储空间
    3. 解析:将符号引用转换成直接引用
  3. 初始化:对类的静态变量,静态代码块执行初始化工作。

构成

 JVM在运行时会有三个ClassLoader,其中他们有父子关系:

  1. 根装载器:使用c++编写,在java中不可见,不是ClassLoader的子类,负责装载jre的核心库类。
  2. ExtClassLoader:是根装载器的子类,负责装载jre扩展目录ext中的jar类包。
  3. AppClassLoader:是ExtClassLoader的子类,负责装载classpath路径下的类包,默认使用该类装载应用程序的类。

全盘负责委托机制

 JVM有全盘负责委托机制,是指当一个ClassLoader载入一个类时,其所依赖和引用的类也由同一个ClassLoader载入;先委托父装载器寻找目标类,只有找不到才从自己的路径中查找并转载目标类。
 这个机制也是导致NoSUchMethodError问题的原因,如果在类路径有多个不同版本的类包就有可能导致错误。

反射机制

 即是可以从Class对象中获取构造函数,成员变量方法类等反射对象即是包括了private或protected成员变量和方法的但是要申明setAccessible(boolean access)
 主要有:

  1. 类的构造函数反射类(Constructor):通过getConstructors(parameterType)方法(或getDeclaredConstructors(parameterType))获取拥有特定入参的构造函数反射对象,并且可以通过newInstance来实例化。
  2. 类方法的反射类:通过getMethods()来获得特定的方法反射类,其最主要的方法是invoke(Object obj, Object[] args)来调用原方法。
  3. 类的成员变量反射类:通过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:返回资源对应的输入流。

具体实现类

  1. WriteableResource:可写资源接口,有两个实现类:FileSystemResource和PathResource。
  2. ByteArrayResource:二进制数组表示的资源。
  3. ClassPathResource:类路径下的资源,资源以相对于类路径的方式表示。
  4. FileSystemResource:文件系统资源,资源用系统路径的方式表示如“D:/XXX/XXX.xml”等。
  5. InputStreamResource:以输入流返回表示的资源。
  6. ServletContextResource:为访问Web容器上下文的资源而设计的类,负责以相对于web应用根目录的路径加载资源,支持以流和URL的方式访问,在war解包的情况下,也可以通过File方式访问。
  7. URLResource:URL封装了java.net.URL可以访问任何通过URL表示的资源。
  8. PathResource:提供的读取资源文件的类,可以访问通过URL,Path,系统文件路径表示的资源。

 在获取资源后,用户就可以通过Reaource接口定义的多个方法来访问文件其他信息,如getFileName()方法来获取文件名,通过getInputStream()方法来获取文件的输入流等。
注意在资源配置文件在项目发布时会被打包,所以不能使用getFile()方法了,而要用getInputSteam(),这个问题码一下。

资源加载

资源地址表达式

 为了访问不同类型的资源,必须使用相应的Resource实现类,spring提供了强大的加载资源机制来简化了这一过程。仅通过资源地址的特殊标识就可以访问相应的资源,还支持ant风格的资源地址。
 有如下较常见的地址前缀:

  1. classpath:/classpath:/:这两个都是相对于类的根路径开始。资源文件可以在文件系统中也可以在jar或zip的类包中。特别注意classpath*:可以扫描所有的同名包并加载所需。
  2. file::使用URLResource从文件系统目录中装载资源,可以是相对路径,也可以是绝对路径。
  3. http://:使用UrlResource从web服务器中装载资源。
  4. ftp://:使用UrlResource从ftp服务器中装载资源
  5. 无前缀:根据ApplicationContext来具体决定。

ant

 ant是一个允许通配符的格式

  1. ?:匹配文件名中的一个字符
  2. *:匹配文件名中的任意字符
  3. **:匹配多层路径
  4. 。。。

资源加载器

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());
	}
}
}


猜你喜欢

转载自blog.csdn.net/real_Rickys/article/details/82966482
今日推荐