精通Spring+4.x++企业开发与实践之IOC容器

#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的功能经过其余接口获得不断的拓展。

    • ListableBeanFactory:该接口定义了访问容器中Bean基本信息的若干方法,例如查看Bean的个数,获取某一类型的Bean配置名,查看容器是否包括某一个Bean等。 containsBeanDefinition getBeanDefinitionCount getBeanDefinitionNames getBeanNamesForType getBeanNamesForType getBeanNamesForType getBeansOfType getBeansOfType getBeanNamesForAnnotation getBeansWithAnnotation findAnnotationOnBean
    • HierachicalBeanFactory:父子级联IoC容器的接口,子容器能够经过接口方法访问父容器的接口。

      getParentBeanFactory
      containsLocalBean
    • CofigurableBeanFactory:这是一个重要的接口加强了IoC容器的可定制性。它定义了设置类装载器的,属性编辑器,容器初始化后置处理器等方法。 setParentBeanFactory setBeanClassLoader getBeanClassLoader setTempClassLoader getTempClassLoader setCacheBeanMetadata isCacheBeanMetadata setBeanExpressionResolver getBeanExpressionResolver setConversionService getConversionService addPropertyEditorRegistrar registerCustomEditor copyRegisteredEditorsTo setTypeConverter getTypeConverter addEmbeddedValueResolver hasEmbeddedValueResolver resolveEmbeddedValue addBeanPostProcessor getBeanPostProcessorCount registerScope getRegisteredScopeNames getRegisteredScope getAccessControlContext copyConfigurationFrom registerAlias resolveAliases getMergedBeanDefinition isFactoryBean setCurrentlyInCreation isCurrentlyInCreation registerDependentBean getDependentBeans getDependenciesForBean destroyBean destroyScopedBean destroySingletons
    • AutowireCapableBeanFactory:定义了将容器中的Bean按照某种规则(名字,类型匹配等)进行自动装配的方法。

      createBean
      autowireBean
      configureBean
      createBean
      autowire
      autowireBeanProperties
      applyBeanPropertyValues
      initializeBean
      applyBeanPostProcessorsBeforeInitialization
      applyBeanPostProcessorsAfterInitialization
      destroyBean
      resolveNamedBean
      resolveDependency
      resolveDependency
    • SingletonBanRegistry:定义容许在运行期间向容器注册单实例Bean的方法,

      registerSingleton
      getSingleton
      containsSingleton
      getSingletonNames
      getSingletonCount
      getSingletonMutex
    • BeanDefinitionRegistry:Spring配置文件中每个<bean></bean>节点元素在Spring容器里都经过一个BeanDefinition对象标识,它描述了Bean的配置信息,而BeanDefinitionRegistry接口提了向容器手工注册BeanDefinition对象的方法。 registerBeanDefinition removeBeanDefinition getBeanDefinition containsBeanDefinition getBeanDefinitionNames getBeanDefinitionCount isBeanNameInUse

#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的销毁方法,那么会执行该方法释放资源。

代码实例连接: https://github.com/chenanddom/SpringSection4/tree/master/src/main/java/com/flexible/beanfactory/beanfactorylifecyle

#ApplicationContext中Bean的生命周期

相关文章
相关标签/搜索