Spring IoC容器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IoC容器相关的知识,希望对你有一定的参考价值。
1、IoC概述
控制反转(Inverse of Control,IoC)是Spring容器的内核,AOP、声明式事务等功能都是在此基础上扩展的。所谓IoC就是通过容器来控制业务对象之间的依赖关系,而不是传统实现中,由代码直接操控。这也就是“控制反转”概念所在:控制权由应用代码中转移到了外部容器,控制权的转移,就是反转。控制权转移带来的好处就是降低了业务对象之间的依赖程度。
更加形象的说明一下IoC是如何做的。这有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
2、BeanFactory和ApplicationContext
Spring通过一个配置文件描述了Bean和Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供了Bean实例化缓存、声明周期管理、Bean实例化代理、事件发布、资源装载等高级服务。
Bean工厂(BeanFactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制。BeanFactory使管理不同类型的Java对象称为可能,应用上下文(ApplicationContext)建立在BeanFactory基础之上,提供了更多面向应用的功能。BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。
ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在获取ApplicationContext实例后,就可以像BeanFactory一样调用getBean(beanName)返回Bean了。ApplicationContext的初始化和BeanFactory的初始化有一个重大的区别:BeanFactory在初始化容器时,并未初始化Bean,直到第一次访问某个Bean时才实例化目标Bean;而ApplicationContext在初始化应用上下文时就实例化所有单实例的Bean。因此ApplicationContext的初始化时间会比BeanFactory稍长一些。
Spring3.0支持基于注解类的配置方式,主要功能来自于Spring的一个名为JavaConfig的子项目,目前JavaConfig已经是Spring核心框架的一部分。一个标注@Configuration注解的POJO即可提供Spring所需的Bean配置信息。
WebApplicationContext是专门为Web应用准备的,它允许从相对于Web根目录的路径中装载配置文件,完成初始化工作。从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象将作为属性防止到ServletContext中,以便Web应用环境可以访问spring应用上下文。Spring专门为此提供了一个工具类WebApplicationContextUtils。通过该类的getWebApplicationContext(ServletContext sc)方法,既可以从ServletContext中获取WebApplicationContext实例。
Spring分别提供了用于启动WebApplicationContext的Servlet和Web容器监听器
org.springframework.web.context.ContextLoaderServlet
org.springframework,web.context.ContextLoaderListener
两者都实现了启动WebApplicationContext实例的逻辑,用户只要根据Web容器的具体情况选择二者之一,并在web.xml中完成配置就可以了。
通过实例认识BeanFactory
package org.worm.biz; import org.apache.log4j.Logger; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.worm.util.LogUtil; /** * @ClassName: Car * @Description: TODO 认识BeanFactory测试用类 * @author Administrator * @date 2016年6月28日 上午10:48:51 * */ public class Car implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{ private static final Logger logger = LogUtil.getLogger(Car.class); private String brand; private String color; private int maxSpeed; private String name; private BeanFactory beanFactory; private String beanName; public Car() { logger.info("调用Car()构造函数"); } public String getBrand() { return brand; } public void setBrand(String brand) { logger.info("调用setBrand()设置属性"); this.brand = brand; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BeanFactory getBeanFactory() { return beanFactory; } public String getBeanName() { return beanName; } public void destroy() throws Exception { // TODO Auto-generated method stub logger.info("调用DispoasbleBean.destroy()."); } public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub logger.info("调用InitializingBean.afterPropertiesSet()"); } public void setBeanName(String name) { // TODO Auto-generated method stub logger.info("调用BeanNameAware.setBeanName()"); this.beanName = name; } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { // TODO Auto-generated method stub logger.info("调用BeanFactoryAware.setBeanFactory()."); this.beanFactory = beanFactory; } @Override public String toString() { return "Car [brand=" + brand + ", color=" + color + ", maxSpeed=" + maxSpeed + "]"; } public void introduce(){ logger.info("introduce:"+this.toString()); } public void myInit(){ logger.info("调用myInit()"); this.maxSpeed = 240; } public void myDestory(){ logger.info("调用买也D额story"); } }
package org.worm.biz.springioc; import org.apache.log4j.Logger; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.worm.biz.Car; import org.worm.util.LogUtil; /** * @ClassName: TestSpringIoC * @Description: TODO 学习了解SpringIoC * @author Administrator * @date 2016年6月28日 上午10:39:27 * */ public class TestSpringIoC { private static final Logger logger = LogUtil.getLogger(TestSpringIoC.class); /** * @Title: testBeanFactory * @Description: TODO 通过实例认识BeanFactory * @param 设定文件 * @return void 返回类型 * @throws */ private static void testBeanFactory(){ ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource res = resolver.getResource("classpath:beans.xml"); BeanFactory bf= new XmlBeanFactory(res); logger.info("init BeanFactory"); Car car = bf.getBean("car", Car.class); car.introduce(); System.out.println("car bean is ready for use!"); } public static void main(String[] args) { // TODO Auto-generated method stub new TestSpringIoC().testBeanFactory(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 注解扫描包 --> <context:component-scan base-package="org.worm.biz"/> <!-- 避免IE执行AJAX时,返回JSON出现下载文件 --> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> </list> </property> </bean> <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="mappingJacksonHttpMessageConverter"/> </list> </property> </bean> <!-- 定义跳转的文件的前后缀 ,视图模式配置--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 --> <!-- <property name="prefix" value="/WEB-INF/jsp/" /> --> <!-- <property name="suffix" value=".jsp" /> --> </bean> <!-- 访问静态资源 --> <!-- <mvc:resources location="/images/" mapping="/images/**"/> --> <!-- <mvc:resources location="/css/" mapping="/css/**"/> --> <!-- <mvc:resources location="/js/" mapping="/js/**"/> --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="utf-8" /> <!-- 设置文件上传的最大尺寸 --> <property name="maxUploadSize" value="10485760000" /> <property name="maxInMemorySize" value="40960" /> </bean> <bean id="car" class="org.worm.biz.Car" p:brand = "红旗CA72" p:color = "黑色" p:maxSpeed = "200"/> </beans>
运行结果:
通过注解配置beans.xml的类Beans.java
package org.worm.biz; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @ClassName: Beans * @Description: TODO 基于注解的配置方式,类似于bens.xml * @author Administrator * @date 2016年6月28日 上午11:40:29 * */ @Configuration public class Beans { @Bean(name = "car") public Car buildCar(){ Car car = new Car(); car.setBrand("红旗CA72_Annotation"); car.setMaxSpeed(200); car.setColor("黑色_Annotation"); return car; } }
加载ApplicationContext
/** * @Title: testApplicationContextWithAnnotatioin * @Description: TODO 实例演示applicationContext * @param 设定文件 * @return void 返回类型 * @throws */ private static void testApplicationContextWithAnnotatioin(){ ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class); Car car = ctx.getBean("car",Car.class); car.introduce(); }
3、资源加载
为了访问不同类型的资源,必须使用相应的Resource实现类,是否可以在不显示使用Resource实现类的情况下,仅通过资源地址的特殊标识就可以加载相应的资源了呢?Spring提供了一个强大的加载资源的机制,不但能够通过“classpath”、"file"等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址
地址前缀 | 示例 | 对应资源类型 |
---|---|---|
classpath: | classpath:org/aku/worm/biz/beans.xml | 从类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的根路径。资源文件可以在标准的文件系统中,可以在jar或者zip的类包中 |
file: | file:/org/aku/worm/biz/beans.xml | 使用UrlResource从文件系统目录中加载资源,可以采用绝对路径或相对路径 |
http:// | http://www.aku.org/resource/beans.xml | 使用UrlResource从Web服务器中装载资源 |
ftp:// | ftp://www.aku.org/resource/beans.xml | 使用UrlResource从FTP服务器中加载资源 |
没有前缀 | org/aku/worm/biz/beans.xml | 根据ApplicationContext具体实现类采用对应的Resource |
classpath*: | classpath*:org/aku/worm/biz/beans.xml | 假设多个Jar包或者文件系统类路径中都拥有一个相同的包名(org.aku.worm)。classpath:只会在第一个加载的org.aku.worm包下查找,而classpath*:会扫描所有这个jar包或者类路径下的org.aku.worm类路径。 |
4、Bean基本配置
4.1、 在<beans>标签内装载bean,bean的id属性是唯一的,此外id的命名需要满足xml对id的命名规范:必须以字母开始,后面可以是字母、数字、连字符、下划线、句号、冒号等完成结束符,逗号和空格等是非法的。
4.2、依赖注入
属性注入,通过setter()方法注入Bean的属性或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,所以属性注入是最常用的注入方式。
构造函数注入,它保证一些必要的属性在Bean实例化时就得到设置,并确保了Bean实例在实例化后就可以使用。可按照类型匹配入参、联合使用类型和索引匹配入参和通过自身类型反射匹配入参
4.3、注入参数详解
字面值,一般指可用字符串表示的值,这些值可以通过<value>标签元素进行注入。在xml中<![CDTAT[]]>的作用是让XML解析器将标签中的字符串当做普通文本对待,以防止某些字符串对xml格式造成破坏
引用其他Bean,通过<ref>元素就可以引用其他Bean,建立起依赖关系
集合类型属性,Spring为集合类型(List、Set、Map和Properties)属性提供了专门的配置元素标签。List属性用<list>。Map属性用<map><entry><key/><value/></entry></map>来配置。Properties可以看成Map类型的特例。<props><prop key></prop></props>。最后集合属性可以通过util命名空间配置集合类型的Bean
4.4、Bean的作用域
在Spring中Bean有5个作用域,singleton(在springIoC容器中,仅存在一个Bean实例),prototype(每次从容器中调用Bean时,都相当于执行了一个new XXXBean()),request(每次HTTP请求都会创建一个新的Bean),session(同一个HTTP Session共享一个Bean),globalSession(同一个全局Session共享一个Bean)。
在Spring中推荐采用配置方式“Scope=<作用域类型>”。
4.5、基于注解的Bean
Spring容器成功启动的三大要件分别是:Bean定义信息、Bean实现类以及Spring本身。Spring提供了3个功能分别对于DAO、Service以及Web层的Controller进行注解。
@Repository:用于对DAO实现类进行注解
@Service:用于对Service进行注解
@Controller:用于对Controller进行注解
5、总结
本文分析了IoC的概念,控制反转其实包含两层意思,“控制”是接口实现类的选择控制权,而“反转”是指这种选择控制权从调用类转移到了外部第三方类或容器中。
BeanFactory、ApplicationContext和WebApplicationContext是Spring框架的3个最核心的接口,框架中其他大部分都是围绕着他们展开、为他们提供支持和服务。Spring提供了一个强大的加载资源的机制,不仅能够通过classpath、file等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址。
本文还讲解了在Spring配置文件中配置Bean的各种知识。
本文出自 “阿酷博客源” 博客,请务必保留此出处http://aku28907.blog.51cto.com/5668513/1793626
以上是关于Spring IoC容器的主要内容,如果未能解决你的问题,请参考以下文章