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(转)(代码片段