ICO:Spring容器的内核,AOP、声明式事务等功能都基于此产生。
ICO不够开门见山,所以后期由Martin Fowler用DI,依赖注入的概念代替了IoC,让调用类对某一接口实现类的依赖由第三方(容器或者协作类)注入,从而移除调用类对某一接口实现类的依赖。
注入方式可以划分为三种类型:构造函数注入、属性注入和接口注入。
Spring支持前两种注入方式。
接口注入方式需要额外声明一个接口,增加了类的数目,并且其效果同属性注入并无区别,所以不提倡采用接口注入的方法。
Spring是这样的一个容器,通过配置文件或注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入工作。
Java允许用户借用Class相关的元信息对象间接调用Class的属性,构造器和方法,就是所谓的反射。
invoke(Object object, Object param)第一个参数是操作目标类实例,第二个对象是目标方法的入参。
Class没有public 的构造方法。Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动创造的。
在java.reflect包中定义了三个最主要的反射类:
1.Constructor:类的构造器反射类,通过Class#getConstructor()方法可以获得类的所有构造函数反射对象数组。通过该类的newInstance(Object[] initargs)可以创建一个对象的实例,相当于new,JDK 5.0之后演化成了newInstance(Object…initargs),使用起来更加方便。
2.Method:类方法的反射类,通过Class#getDeclaredMethods()方法可以获得类的所有方法反射类的数组Method[]。该类的invoker(Object obj, Object[] args)可以调用这个方法,obj是目标对象,args是入参。
3.Field:类的成员变量的反射类,通过Class#getDeclaredFields()方法可以获取类的成员变量的反射对象数组。
Java的反射体系保证了可以通过程序化的方式访问目标类中的所有元素。private和protected的成员变量和方法在JVM安全机制允许的情况下也可以通过反射进行调用。
JDK所提供的访问资源的类并不能很好地满足各种底层资源的访问需求。Spring设计了一个Resource接口,为应用提供了更强的访问底层资源的能力。
其主要方法:
boolean exists():判断资源是否存在
boolean isOpen():判断资源是否打开
URL getURL() throws IOException:在支持的情况下返回底层资源的URL对象
File getFile() throws IOException:在支持的情况下返回底层资源的文件对象
InputStream getInputStream() throws IOException:返回资源对应的输入流
注意:Spring的Resource接口及其实现类可以在脱离Spring框架的情况下使用,它比通过JDK访问资源的API更好用,更强大。
Spring可以在不显式使用Resource实现类的情况下,仅通过资源地址的标识符就可以加载相应的资源。同时支持Ant风格带通配符的资源地址。
如:classpath: file: http:// ftp:// 无前缀。
classpath*:可以加载所有打包JAR包及类路径下具有特定名称的资源。
Ant风格的三种通配符:?文件名任意一个字符 文件名任意字符 *匹配多层路径
PathMatchingResourcePatternResolver可以用于加载带Ant风格的资源路径
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resources[] =resolver.getResources("classpath*:com/baobaotao/**/*.xml");
Spring通过配置文件描述Bean及Bean之间的依赖关系,利用Java预研的反射功能实例化Bean并建立Bean之间的依赖关系。
Spring IOC容器不仅完成了这些功能,还提供了Bean实例缓存,生命周期管理,Bean实例代理,事件发布,资源装载等高级服务。
Bean工厂是Spring框架最核心的接口,提供了高级IOC的配置机制。使管理不同类型的Java对象成为可能。
应用上下文(ApplicationContext)建立在BeanFactory智商,提供了更多面向应用的功能,提供了国际化支持和框架事件体系,更易于创建实际应用。
传统类工厂创建一个或者几个类的实例,而BeanFactory是类的通用工厂,可以创建并管理各种类的对象。被其创建和管理的各种POJO被称为Bean。所有可以被Spring容器实例化并管理的Java类都可以成为Bean。
ApplicationContext的主要实现类是ClassPathXmlApplicationContext和ListableBeanFactory接口,在此之上还通过多个其他接口扩展了BeanFactory的功能。
ConfigurableApplicationContext扩展于ApplicationContext,在原有的start/stop方法基础上增加了refresh()和close(),在应用上下文关闭的情况下调用refresh()即可启动应用上下文,在已经启动的状态下,调用refresh()则清除缓存并重新装载配置信息,调用close()可以关闭应用上下文。
如果配置文件放在类路径下,则用户可以优先使用ClassPathXmlApplicationContext实现类:
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/context/beans.xml");
对于ClassPathXMlApplicationContext来说,路径等同于classpath:com/baobaotao/context/beans.xml
如果配置文件放置在文件系统路径下,则可以优先考虑使用FileSystemXmlApplicationContext实现类:
ApplicationContext ctx = new FileSystemApplicationContext(“com/baobaotao/context/beans.xml”);
对于FileSystemApplicationContext来说,路径等同于file:com/baobaotao/context/bean.xml
在获取了ApplicationContext之后,就可以像BeanFactory一样调用getBean(beanName)的方法返回Bean了。
BeanFactory在使用Bean时才会初始化,而ApplicationContext在初始化应用上下文时就实例化所有单实例的Bean。所以ApplicationContext的初始化要稍微慢一些。
Spring所支持的基于类注解的配置方式,主要功能来自于JavaConfig的子项目,该项目已经升级为Spring核心框架的一部分。
标注位@Configuration注解的POJO即可提供Spring所需的Bean配置信息。
使用如下语句便可以通过ApplicationContext的方式加载Beans.class中定义的Bean定义并调用其实例方法初始化Bean,启动容器并装配Bean。
ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class);
Car car =ctx.getBean(“car”,Car.class);
WebApplicationContext类体系结构
专门为web应用准备,允许从相对于Web根目录的路径中装载配置文件完成初始化工作。整个Web应用上下文对象将作为属性放置到ServletContext中,一边Web应用环境可以访问Spring应用上下文。Spring利用WebApplicationContextUtils的getWebApplicationContext(ServletContext sc)方法,从中加载WebApplicationContext实例。
作用域:
非web环境Bean作用域:
singleton,prototype
web环境:
singleton,prototype,reuqest,session,global session
WebApplicationContext以ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为键放置在ServletContext的属性列表中。
Spring的Web容器:servletContext和Web应用上下文WebApplicationContext之间的互访:
servletContext->WebApplicationContext: getAttribute(WebApplicaiton.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)
WebApplicationContext->servletContext:getServletContext()
WebApplicationContext初始化同BeanFactory和ApplicationContext有所区别,需要ServletContext实例,必须在拥有Web容器的前提下才能完成启动工作。
Spring提供了用于启动WebApplication的Servlet和Web容器监听器:
org.springframework.web.context.ContextLoaderServlet
org.springframework.web.context.ContextLoaderListener
Bean的生命周期包括了从Spring容器着手开始初始化Bean开始到最终Bean的销毁,这其中用了大致三类方法:
1. Bean自身方法:构造函数,Setter设置属性。
2. Bean级生命周期接口
3. 容器生命周期接口方法:InstantiationAwareBeanPostProcessor和BeanPostProcessor两个接口。后处理器,独立于Bean。
Spring容器可以调用多个后处理器。
通过的init-method和destroy-method属性配置方式为Bean指定初始化和销毁的方法,采用这种方式对Bean生命周期的控制效果和通过实现InitializingBean,DisposableBean接口所达到的效果是完全相同的。前者可以使Bean不需要同特定的Spring框架接口绑定,达到了解耦的目的。Spring 2.1中还添加了一个InitDestroyAnnotationBeanPostProcessor,该Bean后处理将对标注了@PostConstruct,@PreDestroy注解的Bean进行处理,在Bean初始化和销毁后执行相应的操作。
BeanPostProcessor接口不要求Bean去继承它,可以完全像插件一样注册到Spring容器中,为容器提供额外的功能。Spring容器充分的利用BeanPostProcessor对Bean进行加工处理,对于一般的应用而言,我们也不大会需要使用这个接口。Spring扩展插件或者Spring子项目可以使用这些后处理器完成很多令人激动的功能。
如果Bean实现了org.springframework.context.ApplicationContextAware接口,会增加一个调用该接口方法
setApplicationContext()的步骤。
ApplicationContext和BeanFactory另一个最大的不同之处在于:前者可以利用Java反射机制自动识别出配置文件中定义的
BeanPostProcessor,InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自动注册到应用上下文中;后者需要
在代码中手工调用addBeanPostProcessor()方法进行注册。所以在开发过程中我们普遍使用ApplicationContext而不是BeanFactroy
。
Spring框架三个最核心的接口:BeanFactory,ApplicationConetxt,WebApplicationContext。
框架通过Resource实现了和具体资源的解耦,不论其在何种存储介质中,都可以通过相同的实例返回。
ResourceLoader通过策略模式,可以通过传入资源地址的信息,自动选择适合的底层资源实现类,为上层对资源的引用提供了极大的便利。