#IOC容器java
#类装载器ClassLoadergit
寻找类的字节码文件并构造出类再JVM内部标识对象的组件。再Java中, 类装载器吧一个类装入JVM,须要入如步骤: (1)装载:查找和导入Class文件. (2)连接:执行校验,准备和解析步骤,其中解析步骤是能够选择的。 1.准备:给类的静态遍历分配存储空间。 2.校验: 检查载入Class文件数据的正确性。 3.解析:将符好引用转换成直接引用。 (3)初始化:对类的静态变量,静态代码块执行初始化工做.
#JVM装载类时使用的机制github
JVM装载类时使用"全盘负责委托机制","全盘负责"是指当一个ClassLoader装载一个类时 ,除非显示的使用另外一个ClassLoader,该类所依赖的类也由这个ClassLoader载入;"委托机制" 是指原先委托父装载器寻找目标类,只有找不到的状况下才从本身的类路径中查找而且装载目标类 ,这也是出于安全考虑。
#Java的反射机制web
Class反射对象描述类雨衣结构,能够从class对象重获取构造函数,成员变量,方法类等类元素的反射对象,并以编程的方式经过这些反射对象对目标类对象进行操做。这些反射对象类在java.reflect包中定义。 - Constructor:类的构造函数反射类,经过Class#getConstructors()方法能够获取类的全部构造函数反射对象数组,在Java5.0中,还能够经过getConstructor(Class...parameterTypes)获取特定入参的构造函数反射对象。Constructor的一个主要方法事newInstance(Object[] initargs),经过改方法能够建立一个对象的实例,至关于使用new关键字。在Java5.0中,改方法演化为更为灵活的形式:newInstance(Onject) - Method:类方法的反射类,经过Class#getDeclaredMethods()方法能够获取类的全部方法反射类对象数组Method[].在Java5.0中,能够经过getDeclaredMethod(String name,Class...parameterTypes)获取特定签名的方法 name是方法名,Class...为方法入参类型列表。Method最主要的方法是invoke(Object obj,Object[] args),其中obj标识操做的目标对象;args为方法入参。Method的其余方法以下 getTypeParameters getReturnType getGenericReturnType getParameterTypes getExceptionTypes - Field:类的成员变量的反射类,经过Class#getDeclaredFields()方法能够获取类的程愿变量反射对象数组,经过Class#getDeclaredField(String name)则能够获取某个特定名称的成员变量反射对象。Field类最主要的方法是set(Object obj,Object value),其中object标识操做的目标对象,经过value为目标对象的成员变量设置值,若是为基础类型可使用Field类中提供的待类型名的值设置方法。
实例: github:https://github.com/chenanddom/SpringSection4/blob/master/src/main/java/com/flexible/ioc/reflect/ReflectDemo.javaspring
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //类装载器获取Car类对象 ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("com.flexible.ioc.reflect.Person"); //获取类的默认构造器对象而且经过它实例化 // Constructor constructor = clazz.getDeclaredConstructor((Class[]) null); Constructor constructor = clazz.getDeclaredConstructor((Class[]) null); Person person = (Person) constructor.newInstance(); //经过反射方法设置属性 Method setUserName = clazz.getMethod("setUserName", String.class); setUserName.invoke(person, "zhangsan"); Method setUserAge = clazz.getMethod("setUserAge", Integer.class); setUserAge.invoke(person, 26); System.out.println(person.toString()); // System.out.println(setUserAge.getReturnType());//获取返回值类型 // System.out.println(setUserAge.getParameterTypes());//获取参数类型 System.out.println(setUserAge.getParameterAnnotations()); System.out.println(loader); System.out.println(loader.getParent()); //根记载器不是ClassLoader的子类,是C++写的,没法获取到 System.out.println(loader.getParent().getParent()); } }
#资源访问编程
JDK缺乏从类路径或者Web容器上下文中获取资源的操做类。Spring针对此限制设计了一个Resource接口,它为应用提供了更强的底层资源访问能力。该接口用于对应的不一样的资源类型的实现类。Resource接口的主要方法以下: //资源是否存在 boolean exists(); //资源是否可读 boolean isReadable(); //资源是否被打开 boolean isOpen(); //若是底层资源能够标识成URL,则该方法返回对应的URL对象 URL getURL() throws IOException; //获取图片的uri URI getURI() throws IOException; //底层资源对应一个文件,则该方法返回对应的File对象 File getFile() throws IOException; // long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String var1) throws IOException; String getFilename(); String getDescription(); //由于集成了InputStreamSource,因此也有获取流的方法 InputStream getInputStream() throws IOException;
Resource在Spring起到了不可获取的做用,Spring框架使用Resource装载各类资源,包括配置文件资源,国际化属性文件资源等。它的具体实现类图以下: 数组
- WritableResource:可写资源接口,Spring3.1新家的接口,实现累如图所示,FileSystemResource和PathResource(Spring4.0加的) - ByteArrayResource->AbstractResource:继承了AbstractResource,标识二进制数组的资源,二进制数组的资源能够在内存中经过程序构造。 - ClassPathResource:类路径下的资源,资源以相对路径的方式标识,若是代码所示:
public class FileSourceDemo { public static void main(String[] args) { String filePath = "E:\\BaiduNetdiskDownload\\wangpan\\SpringSection4\\src\\main\\resources\\conf\\file1.txt"; try { //使用系统文件路径方式加载文件 WritableResource res1 = new PathResource(filePath); //使用类路径方式加载文件 Resource res2 = new ClassPathResource("conf/file1.txt"); //使用WritableResource接口写资源文件 OutputStream stream1 = res1.getOutputStream(); stream1.write("这是使用spring Resource接口的例子".getBytes()); stream1.close(); //使用Resource接口读资源文件 InputStream ins1 = res1.getInputStream(); InputStream ins2 = res2.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int i; while ((i=ins1.read())!=-1){ baos.write(i); } System.out.println(baos.toString()); System.out.println("res1:"+res1.getFilename()); System.out.println("res2:"+res2.getFilename()); } catch (IOException e) { e.printStackTrace(); } } }
-FileSystemResource:文件系统资源,资源以文件系统路径的方式所示,如D:/conf/bean.xml. - InpustreamResource:以输入流返回标识的资源。 - ServletContextResource:为访问Web容器上下文中的资源而设置的类,负责以相对于web应用根目录的路径加载资源,它支持以流和URL的方式访问,在WAR解包的状况下,也能够经过File方式访问。该类还能够直接从jar包中访问资源。 - UrlResource:URL封装了java.net.URL,它使用户可以访问任何能够通URL标识的资源,如文件系统的资源,HTTP资源,FTP资源等。 -PathResource:Spring4.0提供的读取资源文件的新类,Path封装了java.net.URL,java.nio.file.Path(Java7提供),文件系统资源,它使用户呢刚刚访问任何能够经过URL,Path,系统文件路径标识的资源,文件系统,HTTP,FTP资源。
##资源加载 为了访问不类型的资源,须要使用相应的Resource实现类,这是比较麻烦的。可是Spring提供了一套强大的加载资源的的机制,不但能够经过"classpath:","file:"等资源地址前缀识别不一样的资源类型,还支持Ant风格带通配符的资源地址。缓存
资源表达式以下图所示: 安全
##资源加载器session
ResourceLoader接口仅有一个getResource(String location)方阿飞,能够根据一个资源地址加载文件资源。不过,资源地址仅仅支持带自u按类型前缀得表达式,不支持Ant风格得资源路径表达式。ResourcePatternResolver拓展ResourceLoader接口,定义了一个新得接口方法getResources(String locationPattern),该方法支持带资源类型前缀及Ant风格得资源路径表达式。PathMathchingResourcePatternResolver是Spring提供得标准实现类。
代码实现:
package com.flexible.resources; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.util.Arrays; import java.util.List; import static junit.framework.TestCase.assertNotNull; public class PatternResolverDemo { public static void main(String[] args) throws IOException { ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); //加载全部类包com.flexible.resources下的,以.xml为后缀的资源文件 Resource[] resources = resourcePatternResolver.getResources("classpath:com/flexible/resources/**/*.xml"); assertNotNull(resources); List<Resource> resourceList = Arrays.asList(resources); resourceList.forEach(e->{ System.out.println(e.getFilename()); }); } }
提示: 使用Resource操做文件时,若是资源配置文件在项目发布时会被达到JAR中,,那么不能使用Resource#getFile()方法,不然会被抛出FileNotFoundException.可是可使用Resource#getInputStream方法读取。 错误的方式: (new DefaultResourceLoader()).getResource("classpath:conf/sys.properties").getFile() 正确的读取方式: (new DefaultResourceLoader()).getResource("classpath:conf/sys.properties").getInputStream() 在Jar包中getFile()没法读取,应该尽可能使用流来处理。
#BeanFactory和ApplicationContext 在Spring中是经过配置文件描述Bean和Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并简历 Bean之间的依赖关系。除此以外还提供了Bean的实例缓存,生命周期管理,Bean实例代理,事件发布,资源装载等高级服务。 通常称BeanFactory为IoC容器,而称ApplicationContext为应用上下文,可是为了方便也将ApplicationContext成为Spring容器。BeanFactory是面向Spring自己的,ApplicationContext是面向开发者的。
###BeanFactory 能够被建立和管理的Java对象常被成为Bean,可是这个JavaBean是要知足必定的规范的,例如须要提供ige默认的不带参数的构造函数,不依赖于某特定的容器等,可是Spring的Bean比JavaBean更加的普遍一些,因此能够被Spring容器实例化并甘丽的Java类能够成为Bean。
BeanFactory接口位于类结构树的顶端,它最主要的方法就是getBean(String beanName),该方法从容器中返回特定名称的Bean.BeanFactory的功能经过其余接口获得不断的拓展。
HierachicalBeanFactory:父子级联IoC容器的接口,子容器能够经过接口方法访问父容器的接口。
getParentBeanFactory containsLocalBean
AutowireCapableBeanFactory:定义了将容器中的Bean按照某种规则(名字,类型匹配等)进行自动装配的方法。
createBean autowireBean configureBean createBean autowire autowireBeanProperties applyBeanPropertyValues initializeBean applyBeanPostProcessorsBeforeInitialization applyBeanPostProcessorsAfterInitialization destroyBean resolveNamedBean resolveDependency resolveDependency
SingletonBanRegistry:定义容许在运行期间向容器注册单实例Bean的方法,
registerSingleton getSingleton containsSingleton getSingletonNames getSingletonCount getSingletonMutex
#WebApplicationContext类体结构 WebApplicationContext是专门为Web准备的,它容许从相对于web根目录的路径装载配置文件完成初始化工做。从WebApplicationContext中能够得到ServletContext的引用,整个Web应用上下文对象将做为属性放置到ServletContext中,以便Web应用环境能够访问Spring应用上下文。Spring专门为此提供了已个工具类WebApplicationContextUtils,经过该类的getWebApplicationContext(ServletContext sc)方法,能够从ServletContext中获取WebApplicationContext实例。WebApplicationContext下的Bean除了singleton和prototype两种做用域以外还有request,session和global session
因为Web应用比通常的应用有更多的特性,所以WebApplicationContext拓展了ApplicationContext.WebApplicationContext定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文起到的时候,WebApplicationContext实例即以此为键放置在ServletContext的属性列表中,能够经过如下语句从Web容器中获取WebApplicationContext:
WebApplication wac = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
这个就是WebApplicationContextUtils工具类getWebApplicationContext(ServletContext sc)方法的内部实现方式,这样Spring的Web应用上下文就和Web容器上下文应用就能够实现互访。
ConfigurableWebApplicationContext拓展了WebApplication,它容许经过配置的方式实例化WebApplicationContext,同时定义了两个重要的方法
void setServletContext(ServletContext servletContext);为spring设置web应用上下文,以便两者结合
void setConfigLocations(String... configLocations);容许加载带前缀的配置文件
###父子容器
经过HierachicalBeanFactory接口,Spring的IoC容器能够简历父子层级关联的容器体系,子容器能够访问父容器的Bean,可是父容器没法访问自容器的内容,SpringMvc中,展示层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中,这样展示层就能够引用业务层和持久层。而业务和持久层看不到展示层的Bean。
#Bean的生命周期
###BeanFactory中Bean的生命周期 具体的过程以下:
1.当调用者经过getBean(beanName)向容器请求某一个Bean时,若是容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,则在实例化Bean以前,将调用postProcessBeforeInstantiation()方法 2.根据配置文件的状况调用Bean构造函数或者工厂方法实例化Bean。 3.若是容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor,那么实例化Bean以后调用接口postProcessAfterInstantiation()方法,能够装载这里对已经实例化的对象进行一些"装饰" 4.若是Bean配置了属性信息,那么容器在这一步着手将配置文件中的属性值设置到对应的属性,设置每一个属性以前先调用org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口的postProcessPropertyValue()方法。 5.调用Bean的属性设置方法设置属性 6.若是Bean实现了org.springframework.beans.factory.BeanNameAware接口,那么简化调用setBeanName()接口方法,将配置文件中搞Bean对应的名称设置到Bean中。 7.若是Bean实现了org.springframework.beans.factory.BeanFactoryAware接口,则将调用setBeanFactory()接口方法,将BeanFactory容器实例设置给Bean。 8.若是BeanFactory装配了org.springframework.beans.factory.config.BeanPostProcessor后处理器,则将调用 postProcessBeforeInitialization(Object bean, String beanName)接口方法对Bean进行加工操做,bean就是当前须要加工操做的Bean,而BeanName就是当前Bean的配置名。返回的对现货加工处理后的Bean。这个是实现AOP的重要基石。 9.若是Bean实现了org.springframework.beans.factory.InitializingBean接口则调用 void afterPropertiesSet() 方法 10.若是<bean>中荣光init-method属性定义了初始化方法,则将执行这个方法。 11.BeanPostProcessor后处理器定义了两个方法,一.Object postProcessBeforeInitialization(Object bean, String beanName)步骤8调用。二.Object postProcessAfterInitialization(Object bean, String beanName) ,此时调用它能够得到对Bean的再次加工。 12.做用域是prototype的将返回生成的bean给调用者,调用者负责该bean的生命周期,若是是singleton,那么则将Bean放入SpringIoC容器的缓冲池中,而且将Bean引用返回给调用者,Spring继续对这些Bean进行后续的生命周期的维护。 13.做用域是singleton的Bean,当容器关闭,若是实现DisposableBean接口,则将调用接口的destroy()方法,能够编写释放资源,记录日志等操做。 14.对于singleton的Bean,若是配置了destroy-method属性指定了Bean的销毁方法,那么会执行该方法释放资源。
#ApplicationContext中Bean的生命周期