如下整理自http://jinnianshilongnian.iteye.com/blog/1413846,若有侵权当即删除。
Iochtml
Ioc(Inversion of Control),即控制反转。不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。 传统Java SE程序设计,咱们直接在对象内部经过new进行建立对象,是程序主动去建立依赖对象;而IoC是有专门一个容器来建立这些对象,即由Ioc容器来控制对象的建立;IoC 容器控制了对象(主要控制了外部资源获取,不仅是对象包括好比文件等)。
传统应用程序是由咱们本身在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙建立及注入依赖对象;为什么是反转?由于由容器帮咱们查找及注入依赖对象,对象只是被动的接受依赖对象,因此是反转;哪些方面反转了?依赖对象的获取被反转了。
Ioc 容器java
IoC容器就是具备依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际表明者。web
Spring IoC容器如何知道哪些是它管理的对象呢?这就须要配置文件,Spring IoC容器经过读取配置文件中的配置元数据,经过元数据对应用中的各个对象进行实例化及装配。通常使用基于xml配置文件进行配置元数据,并且Spring与配置文件彻底解耦的,可使用其余任何可能的方式进行配置元数据,好比注解、基于java文件的、基于属性文件的配置均可以。
Spring Ioc容器的表明就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不一样层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增长了更多支持企业级功能支持。ApplicationContext彻底继承BeanFactory,于是BeanFactory所具备的语义也适用于ApplicationContext。
容器实现一览:
• XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,能够从classpath或文件系统等获取资源;
(1) File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);spring
(2)Resource resource = new ClassPathResource("classpath.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Deprecated. as of Spring 3.1 in favor of DefaultListableBeanFactory
and XmlBeanDefinitionReader
编程
• ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件;
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");数组
• FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件。
BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");
ide
ApplicationContext接口获取Bean方法简介:测试
• Object getBean(String name) 根据名称返回一个Bean,客户端须要本身进行类型转换;
• T getBean(String name, Class<T> requiredType) 根据名称和指定的类型返回一个Bean,客户端无需本身进行类型转换,若是类型转换失败,容器抛出异常;
• T getBean(Class<T> requiredType) 根据指定的类型返回一个Bean,客户端无需本身进行类型转换,若是没有或有多于一个Bean存在容器将抛出异常;
• Map<String, T> getBeansOfType(Class<T> type) 根据指定的类型返回一个键值为名字和值为Bean对象的 Map,若是没有Bean对象存在则返回空的Map。
示例:
项目结构图,注意fileSystemConfig.xml的位置。用于文件系统配置的读取 ui
HelloApi.java和HelloImpl.java是一个简单的接口及其实现,打印一句Hello World!,bean.xml和fileSystemConfig.xml内容相同,都只有一句简单的对bean的配置:<bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean>
测试代码演示了使用不一样的Ioc容器实现去读取类路径配置文件和文件系统文件的方式:
this
public class HelloServiceTest { @SuppressWarnings("deprecation") @Test public void testXmlBeanFactoryBaseOnFileSystem() { // 1.准备配置文件,从文件系统获取配置文件,默认是相对路径,能够指定绝对路径 File file = new File("fileSystemConfig.xml"); Resource resource = new FileSystemResource(file); // 2.初始化容器 BeanFactory beanFactory = new XmlBeanFactory(resource); // 二、从容器中获取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、执行业务逻辑 helloApi.sayHello(); } @SuppressWarnings("deprecation") @Test public void testXmlBeanFactoryBaseOnClassPath() { // 1.准备配置文件,从当前类加载路径中获取配置文件 Resource resource = new ClassPathResource("bean.xml"); // 2.初始化容器 BeanFactory beanFactory = new XmlBeanFactory(resource); // 二、从容器中获取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、执行业务逻辑 helloApi.sayHello(); } @Test public void testClassPathXmlApplicationContextBaseOnClassPath() { // 1.准备配置文件,从当前类加载路径中获取配置文件 // 2.初始化容器 BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml"); // 二、从容器中获取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、执行业务逻辑 helloApi.sayHello(); } @Test public void testFileSystemApplicationContextBaseOnFileSystem() { // 1.准备配置文件,从文件系统获取配置文件,默认是相对路径,能够指定绝对路径 // 2.初始化容器 BeanFactory beanFactory = new FileSystemXmlApplicationContext( "fileSystemConfig.xml"); // 二、从容器中获取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); // 三、执行业务逻辑 helloApi.sayHello(); } }
XML配置文件的结构
<beans> <import resource=”resource1.xml”/> <bean id=”bean1”class=””></bean> <bean id=”bean2”class=””></bean> <bean name=”bean2”class=””></bean> <alias alias="bean3" name="bean2"/> <import resource=”resource2.xml”/> </beans>
一、<bean>标签主要用来进行Bean定义;
二、alias用于定义Bean别名的;
三、import用于导入其余配置文件的Bean定义,这是为了加载多个配置文件,固然也能够把这些配置文件构造为一个数组(new String[] {“config1.xml”, config2.xml})传给ApplicationContext实现进行加载多个配置文件,那一个更适合由用户决定;这两种方式都是经过调用Bean Definition Reader 读取Bean定义,内部实现没有任何区别。<import>标签能够放在<beans>下的任何位置,没有顺序关系。
Bean
由IoC容器管理的那些组成你应用程序的对象咱们就叫它Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此以外,bean就与应用程序中的其余对象没有什么区别了。那IoC怎样肯定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?这就须要配置元数据,在Spring中由BeanDefinition表明,后边会详细介绍,配置元数据指定如何实例化Bean、如何组装Bean等。
Bean的配置
Spring IoC容器目的就是管理Bean,这些Bean将根据配置文件中的Bean定义进行建立,而Bean定义在容器内部由BeanDefinition对象表示,该定义主要包含如下信息:
● 全限定类名(FQN):用于定义Bean的实现类;
● Bean行为定义:这些定义了Bean在容器中的行为;包括做用域(单例、原型建立)、是否惰性初始化及生命周期等;
● Bean建立方式定义:说明是经过构造器仍是工厂方法建立Bean;
● Bean之间关系定义:即对其余bean的引用,也就是依赖关系定义,这些引用bean也能够称之为同事bean 或依赖bean,也就是依赖注入。
Bean定义只有“全限定类名”在当使用构造器或静态工厂方法进行实例化bean时是必须的,其余都是可选的定义。难道Spring只能经过配置方式来建立Bean吗?回答固然不是,某些SingletonBeanRegistry接口实现类实现也容许将那些非BeanFactory建立的、已有的用户对象注册到容器中,这些对象必须是共享的,好比使用DefaultListableBeanFactory 的registerSingleton() 方法。不过建议采用元数据定义。
BeanDefinition
spring能够经过xml配置文件定义bean,beanFactory能够建立、查找配置文件中定义的这些bean,spring内部是如何将配置文件中所定义的bean变成可让beanFactory建立与管理的呢?这是依靠BeanDefinition进行实现。BeanDefinition是一个接口,它描述了一个bean的实例,保存了bean的定义信息,是bean在内存中的描述形式。xml配置文件所定义的每一个bean在内存中都有对应的Bedifinition对象进行描述。BeanFactory在查找,建立及管理bean时,会先查找其在内存中所保存的BeanDefinition,而后再根据BeanDefinition中的bean描述内容建立bean或返回所需的bean信息。
根据面向接口编程的原则,spring定义了接口BeanDefinitionRegistry注册管理全部的Bedifinition,实现此接口就能够管理bean的定义,DefaultListableBeanFactory类实现了此接口,所以DefaultListableBeanFactory类及其子类具备管理beanDefinition的功能。
Spring读取分析配置文件,根据配置文件中的定义,为这些bean建立对应的BeanDifinition,并将BeanDifinition注册至beanFactory中(具体表现为注册在DefaultListableBeanFactory类型的beanFactory)。当用户须要使用bean时,将传入bean的名称或类型给beanFactory,beanFactory从其所保存的beanDefinition中查找,当找到符合条件的beanDefinition后,则将根据beanDefinition中的bean信息建立bean对象,并返回给用户。
实例化Bean
Spring IoC容器如何实例化Bean呢?
传统应用程序能够经过new和反射方式进行实例化Bean。而Spring IoC容器则须要根据Bean定义里的配置元数据使用反射机制来建立Bean。在Spring IoC容器中根据Bean定义建立Bean主要有如下几种方式:
一、使用构造器实例化Bean,这是最简单的方式,Spring IoC容器即能使用默认空构造器也能使用有参数构造器两种方式建立Bean
二、使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,并且使用静态工厂方法也容许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean
三、使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,并且使用实例工厂方法容许指定方法参数,方式和使用构造器方式同样
示例:
一、构造器实例化Bean:
package cn.nevo.service.impl; import cn.nevo.service.HelloApi; public class HelloImpl implements HelloApi { private String message; public HelloImpl() { this.message = "Hello World!"; } public HelloImpl(String message) { this.message = message; } @Override public void sayHello() { System.out.println(message); } }
<!-- 使用默认构造参数实例化bean --> <bean id="hello" class="cn.nevo.service.impl.HelloImpl"></bean> <!-- 使用有参构造参数实例化bean --> <bean id="hello2" class="cn.nevo.service.impl.HelloImpl"> <constructor-arg index="0" value="New Hello World!"/> </bean>
public class HelloServiceTest { @Test public void testClassPathXmlApplicationContextBaseOnClassPath() { // 1.准备配置文件,从当前类加载路径中获取配置文件 // 2.初始化容器 BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean.xml"); // 二、从容器中获取Bean HelloApi helloApi = beanFactory.getBean("hello", HelloApi.class); HelloApi helloApi2 = beanFactory.getBean("hello2", HelloApi.class); // 三、执行业务逻辑 helloApi.sayHello(); helloApi2.sayHello(); } }
package cn.nevo.service.impl.staticfactory; import cn.nevo.service.HelloApi; import cn.nevo.service.impl.HelloImpl; public class HelloImplStaticFactory { public static HelloApi getInstance(String message) { return new HelloImpl(message); } }
<!-- 使用静态工厂方法实例化bean --> <bean id="statichello" class="cn.nevo.service.impl.staticfactory.HelloImplStaticFactory" factory-method="getInstance"> <constructor-arg index="0" value="static factory instance"/> </bean>
HelloApi helloApi3 = beanFactory.getBean("statichello", HelloApi.class); helloApi3.sayHello();
package cn.nevo.service.impl.instancefactory; import cn.nevo.service.HelloApi; import cn.nevo.service.impl.HelloImpl; public class HelloImplInstanceFactory { public HelloApi getInstance(String message) { return new HelloImpl(message); } }
<!-- 使用实例工厂方法实例化bean --> <bean id="instancehello" class="cn.nevo.service.impl.instancefactory.HelloImplInstanceFactory"/> <bean id="instance" factory-bean="instancehello" factory-method="getInstance"> <constructor-arg index="0" value="instance factory"/> </bean>
测试
HelloApi helloApi4 = beanFactory.getBean("instance", HelloApi.class); helloApi4.sayHello();