Spring03---IOC
Posted Hermioner
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring03---IOC相关的知识,希望对你有一定的参考价值。
一. 基础概念
1. 什么是IOC
Ioc-----Inversion of control,即“控制反转”,它只是一种设计思想。它意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
(1)谁控制谁
传统的是通过new来创建对象;但是IOC思想是通过一个专门的容器来创建这些对象。即:IOC容器控制了对象。
(2)控制了什么
主要是控制了外部资源的获取(不仅是对象,还包含文件等资源的获取)
(3)为何是反转
因为容器帮我们查找及注入依赖对象,对象只是被动的接收依赖对象
(4)哪些地方反转了
依赖对象的获取被反转了
(5)Spring IOC容器如何知道哪些是它管理的对象呢
这就需要配置文件。容器是通过读取配置文件中的配置元数据来实现管理的。(比如读取bean id)配置文件可以是xml,注解,Java文件等等,这些都是和spring完全解耦的。
(6)Spring IOC容器管理的对象叫什么
Bean
note:在Spring种BeanFactory是IOC容器的实际代表者。
2. 什么是Bean
Bean就是由Spring容器初始化、装配及管理的对象。
Bean定义在容器内部用BeanDefinition对象表示。
二. IOC的配置使用
一般配置文件结构如下:
<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定义,当然也可以通过将多个配置文件以数组的形式传入ApplicationContext
每个Bean可以由一个或多个id,将第一个id称为“标识符”,其余id都叫做“别名”。这些id在IOC容器中必须唯一。
有以下几种方式为Bean指定id:
1. 不指定id,只配置必须的全限定类名,由IOC容器为其生成一个标识,客户端必须通过接口 ” T getBean(Class<T> requiredType) ” 获取Bean;
<bean class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/> @Test public void test1() { BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean1.xml"); //根据类型获取bean HelloApi helloApi = beanFactory.getBean(HelloApi.class); helloApi.sayHello(); }
2. 指定id,必须在IOC容器种唯一;
<bean id=” bean” class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/> @Test public void test2() { BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean2.xml"); //根据id获取bean HelloApi bean = beanFactory.getBean("bean", HelloApi.class); bean.sayHello(); }
3. 指定name,这样name就是标识符,必须在IOC容器种唯一;
<bean name=” bean” class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/> @Test public void test3() { BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean3.xml"); //根据name获取bean HelloApi bean = beanFactory.getBean("bean", HelloApi.class); bean.sayHello(); }
以上的测试代码片段如下:
@Test public void test3() { BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean3.xml"); //根据name获取bean HelloApi bean = beanFactory.getBean("bean", HelloApi.class); bean.sayHello(); }
4. 指定id和name,id就是标识符,而name就是别名,必须在IOC容器中唯一;
<bean id=”bean1”name=”alias1” class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/> <!-- 如果id和name一样,IoC容器能检测到,并消除冲突 --> <bean id="bean3" name="bean3" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
@Test public void test4() { BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean4.xml"); //根据id获取bean HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);//OK bean1.sayHello(); //根据别名获取bean HelloApi bean2 = beanFactory.getBean("alias1", HelloApi.class); //OK bean2.sayHello(); //根据id获取bean HelloApi bean3 = beanFactory.getBean("bean3", HelloApi.class); bean3.sayHello(); String[] bean3Alias = beanFactory.getAliases("bean3"); //因此别名不能和id一样,如果一样则由IoC容器负责消除冲突 Assert.assertEquals(0, bean3Alias.length);
}
note:当别名和id相同,IOC会自动消除别名,因此最终别名的Length是0
5. 指定多个name,多个name用逗号,分号,双引号分割,第一个被用作标识符,其它的都是别名,所有标识符必须在IOC容器中唯一;
<bean name=” bean1;alias11,alias12;alias13 alias14” class=” cn.javass.spring.chapter2.helloworld.HelloImpl”/>
也可以通过别名获取对象。
6. 使用<alias>标签指定别名,别名也必须在IOC容器中唯一;
<bean name="bean" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
<alias alias="alias1" name="bean"/>
<alias alias="alias2" name="bean"/>
note: 从上面的定义来看,name或id如果指定它们种的一个时都作为标识符,那为什么还需要id和name同时存在呢?
这是因为 当使用基于XML的配置元数据时,在XML中id是一个真正的XML id属性,因此当其他的定义来引用这个id时就体现出id 的好处了,可以利用XML解析器来验证引用的这个id是否存在,从而更早的发现是否引用了一个不存在的bean,而使 用name,则可能要在真正使用bean时才能发现引用一个不存在的bean。
三. 实例化Bean
Spring IoC容器根据Bean定义里的配置元数据使用反射机制来创建Bean。
在Spring IoC容器中根据Bean定义创建Bean主要有以下几种方式:
1. 使用构造器实例化Bean(最简单)
Ioc容器既能使用默认空构造器,也能使用有参数构造器两种方式创建Bean.
//空构造器 <bean name="bean1" class="cn.javass.spring.chapter2.HelloImpl2"/> //有参构造器 <bean name="bean2" class="cn.javass.spring.chapter2.HelloImpl2"> <!-- 指定构造器参数 --> <constructor-arg index="0" value="Hello Spring!"/> </bean>
note:< constructor-arg >标签指定构造器参数值,其中index表示位 置,value表示常量值,也可以指定引用,指定引用使用ref来引用另一个Bean定义
eg:
<bean id="bean1" class="com.test.spring.Hello"/> <bean id="bean2" class="com.test.spring.Hello"> <constructor-arg index="0" value="Hermioner"/> <constructor-arg index="1" value="Nice"/> </bean>
public class Hello { private String name; private String nice; public Hello() { this.name="Hermioner"; this.nice="Nice"; } public Hello(String name,String nice) { this.name=name; this.nice=nice; } public void sayHello() { System.out.println("hello world"); System.out.println(name); System.out.println(nice); } }
public class HelloTest { @Test public void testHelloWorld() { BeanFactory beanFactory=new ClassPathXmlApplicationContext("bean.xml"); Hello hello=beanFactory.getBean("bean1",Hello.class); hello.sayHello(); Hello hello2=beanFactory.getBean("bean2",Hello.class); hello2.sayHello(); } }
hello world
Hermioner
Nice
hello world
Hermioner
Nice
2. 使用静态工厂方式实例化Bean
,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实 例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取 Bean,配置如下所示:
<bean id="bean" class="com.test.spring.MyStaticFactory" factory-method="newInstance"> <constructor-arg index="0" value="Hermioner"/> <constructor-arg index="1" value="Nice"/> </bean> public class MyStaticFactory { public static Hello newInstance(String name,String nice) { return new Hello(name,nice); } } public class Hello { private String name; private String nice; public Hello() { this.name="Hermioner"; this.nice="Nice"; } public Hello(String name,String nice) { this.name=name; this.nice=nice; } public void sayHello() { System.out.println("hello world"); System.out.println(name); System.out.println(nice); } } public class HelloTest { @Test public void testHelloWorld() { BeanFactory beanFactory=new ClassPathXmlApplicationContext("bean.xml"); Hello hello=beanFactory.getBean("bean",Hello.class); hello.sayHello(); } }
hello world
Hermioner
Nice
3. 使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂 Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方 式一样,配置如下
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "> <!-- 1.定义实例化工厂Bean --> <bean id="beanInstanceFactory" class="com.test.spring.MyInstanceFactory"/> <!-- 2.使用实例工厂Bean创建Bean --> <bean id="bean" factory-bean="beanInstanceFactory" factory-method="newInstance"> <constructor-arg index="0" value="Hermioner"/> <constructor-arg index="1" value="Hermioner"/> </bean> </beans>
public class MyInstanceFactory { public Hello newInstance(String name,String nice) { return new Hello(name,nice); } }
public class Hello { private String name; private String nice; public Hello() { this.name="Hermioner"; this.nice="Nice"; } public Hello(String name,String nice) { this.name=name; this.nice=nice; } public void sayHello() { System.out.println("hello world"); System.out.println(name); System.out.println(nice); } }
public class HelloTest { @Test public void testHelloWorld() { BeanFactory beanFactory=new ClassPathXmlApplicationContext("bean.xml"); Hello hello=beanFactory.getBean("bean",Hello.class); hello.sayHello(); } }
hello world
Hermioner
Hermioner
note:
通过以上例子我们已经基本掌握了如何实例化Bean了,大家是否注意到?这三种方式只是配置不一样,从获取方 式看完全一样,没有任何不同。这也是Spring IoC的魅力,Spring IoC帮你创建Bean,我们只管使用就可以了,是不是 很简单。
总结:
到此我们已经讲完了Spring IoC基础部分,包括IoC容器概念,如何实例化容器,Bean配置、命名及实例化, Bean获取等等。不知大家是否注意到到目前为止,我们只能通过简单的实例化Bean,没有涉及Bean之间关系。接下来 一章让我们进入配置Bean之间关系章节,也就是依赖注入。
参考文献:
http://jinnianshilongnian.iteye.com
以上是关于Spring03---IOC的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
Spring boot:thymeleaf 没有正确渲染片段
What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段
spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段
Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]
解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段