spring IoC基础(二)

1、IoC是什么

  IOC——Inversion of Control,即控制反转,不是什么技术,而是一种设计思想。在Java开发中,IoC意味着将你设计好的对象交给容器控制,而不是传统的直接在你的对象内部控制。

  • 谁控制谁,控制什么:传统的JavaSE程序设计,我们直接在对象内部通过new关键字进行对象的创建,是程序主动去创建依赖的对象;而IoC有一个专门的容器来创建对象,即由IoC容器来控制对象的创建;谁控制谁?当然是IoC容器控制对象;控制什么?主要控制了外部资源的获取(不只对象包括比如文件等)。
  • 为何是反转,那些方面反转:有反转就有正转,传统应用程序是由我们自己在对象中主动控制直接获取依赖对象,也就是正转;而反转则是由容器帮忙创建及注入依赖对象;为何是反转?因为由容器帮助我们查找及注入依赖对象。对象只是被动的接受依赖对象,所以是反转。

            

2、DI是什么

  DI——Dependency Injection,即依赖注入,是组件之间的依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件儿中。依赖注入的目的并非为软件系统带来更多的功能,而是为了提升组件的复用性。

  • 谁依赖谁:当然是某个IoC容器管理对象依赖于容器,“被注入对象的对象”依赖于“依赖对象”。
  • 为什么需要依赖:容器管理对象需要IoC容器来提供对象需要的外部资源。
  • 谁注入谁:很明显是IoC容器注入某个对象,也就是注入依赖对象。
  • 注入了什么:就是注入某个对象需要的外部资源

  IoC和DI其实它们是同一个概念的不同角度描述,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”

3、IoC容器

  IoC容器就是拥有依赖注入功能的容器,IoC容器负责实例化,定位,配置应用程序中的对象及监理这些对象之间的依赖。应用程序无需再直接通过new关键字创建对象,应用程序由IoC容器进行组装。在spring中BeanFactory是IoC容器的实际代表者。

4、Bean

  由IoC容器管理的那些组成应用程序的对象我们叫它bean,bean是由spring容器初始化,装配及管理的对象,除此之外没有什么不同。IoC容器实例化管理bean需要配置元数据,在spring中由BeanDefinition代表。

5、详解IoC容器

  在spring中IoC容器的带包就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本的功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与spring aop集

  成、国际化处理、事件传播及提供不同层次的Context实现。简单说就是BeanFactory提供了IoC容器最基本的功能,而ApplicationContext则增加了更多企业级功能支持。ApplicationContext完全集成BeanFactory,因而BeanFactory所具有的

  语义也适用于ApplicationContext。

  容器实现一览:

    XMLBeanFactory:BeanFactory实现,提供了基本的IoC功能,可以从classpath或文件系统获取资源:

1 File file = new File("fileSystemConfig.xml");
2 Resource resource = new FileSystemResource(file);
3 BeanFactory beanFactory = new XmlBeanFactory(resource);
4 
5 Resource resource = new ClassPathResource("classpath.xml");
6 BeanFactory beanFactory = new XmlBeanFactory(resource);

    ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件:

1 BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");

    FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件:

1 BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");

    ApplicationContext接口获取bean方法简介:

1 Object getBean(String name)                   //根据名称返回一个Bean,客户端需要自己进行类型转换;
2 T getBean(String name, Class<T> requiredType) //根据名称和指定的类型返回一个Bean,客户端无需自己进行类型转换,如果类型转换失败,容器抛出异常;
3 T getBean(Class<T> requiredType)              //根据指定的类型返回一个 Bean,客户端无需自己进行类型转换,如果没有或有多于一个Bean存在容器将抛出异常;
4 Map<String, T> getBeansOfType(Class<T> type)  //根据指定的类型返回一个键值为名字和值为Bean对象的Map,如果没有Bean对象存在则返回空的Map

6、IoC容器如何工作  

  • 准备配置文件:在配置文件中声明bean定义也就是为bean配置元数据。
  • 由IoC容器解析元数据:IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装bean。
  • 实例化IoC容器:由客户端实例化容器,获取需要的bean。

  

7、IoC容器配置使用

  一般配置文件如下

1 <beans>
2  <import resource="resource1.xml"/>
3  <bean id="bean1" class=""></bean>
4  <bean id="bean2" class=""></bean>
5  <bean name="bean2" class=""></bean>
6  <alias alias="bean3" name="bean2"/>
7  <import resource="resource2.xml"/>
8 </beans>
  • bean标签主要用来进行bean定义;
  • alias用于定义bean别名;
  • import用于导入其他配置文件的bean定义这个是为了加载多个配置文件,当然也可以把这些配置文件构造为一个数组(new String[]{“config1.xml”,“config2.xml”})传给ApplicationContext实现进行多个配置文件加载。

  7.1 bean的配置

    spring IoC容器目的就是管理bean,这些bean将根据配置文件的定义进行创建,而bean定义在容器内部由BeanDefinition对象表示,该对象主要有以下含义:

      。全限定类名:用于定义bean的实现类

      。bean行为定义:这些定义了bean在容器中的行为;包括作用域(单例,原型创建)、是否惰性初始化及生命周期

      。bean创建方式定义:说明是通过构造器还是工厂方法创建bean

      。bean之间关系定义:即对其他bean的引用,也就是依赖关系定义

    bean不仅是只能通过配置方式创建,某些SingletonBeanRegistry接口实现类实现也允许将那些非BeanFactory创建、已有的用户对象注册到容器中,这些对象必须是共享的,不过建议采用配置的方式定义。

  7.2 bean的命名

    每个bean可以有一个或多个id,在这里我们把第一个id称为“标识符”,其余的id称为“别名”;这些id在IoC容器中必须唯一。

    。不指定id,只配置必须得全限定类名

1 <bean class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> 
1 @Test
2 public void test1() {
3   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean1.xml");
4    //根据类型获取 bean
5    HelloApi helloApi = beanFactory.getBean(HelloApi.class);
6    helloApi.sayHello();
7 }

    。指定id,必须在IoC容器中唯一

1 <bean id="bean" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> 
1 @Test
2 public void test2() {
3   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean2.xml");
4   //根据id获取bean
5    HelloApi bean = beanFactory.getBean("bean", HelloApi.class);
6    bean.sayHello();
7 }

   。指定name,这样name就是标识符,标识符必须在IoC容器中唯一

1 <bean name="bean" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> 
1 @Test
2 public void test3() {
3    BeanFactory beanFactory =  new ClassPathXmlApplicationContext("chapter2/namingbean3.xml");
4    //根据 name 获取 bean
5   HelloApi bean = beanFactory.getBean("bean", HelloApi.class);
6   bean.sayHello();
7}

  。指定id和name,id是标识符,name是别名,同样标识符必须在IoC容器中唯一

1 <bean id="bean1" name="alias1" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
2 <!-- 如果id和name一样,IoC容器能检测到,并消除冲突 -->
3 <bean id="bean3" name="bean3" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> 
 1 @Test
 2 public void test4() {
 3   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/namingbean4.xml");
 5    //根据id获取bean
 6   HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);
 7   bean1.sayHello();
 8   //根据别名获取bean
 9   HelloApi bean2 = beanFactory.getBean("alias1", HelloApi.class);
10   bean2.sayHello();
11   //根据id获取bean
12   HelloApi bean3 = beanFactory.getBean("bean3", HelloApi.class);
13   bean3.sayHello();
14   String[] bean3Alias = beanFactory.getAliases("bean3");
15   //因此别名不能和id一样,如果一样则由IoC容器负责消除冲突
16   Assert.assertEquals(0, bean3Alias.length);
17 }

  。指定多个name,多个name用“,”、“;”、“ ”分割,第一个被作为标识符,其他的被作为别名

  。用alias标签指定别名,别名也必须在IoC容器中唯一

  注:bean的命名约定

    bean的命名必须遵循xml命名规范,但最好符合Java命名规范,由字母、数字、下划线组成驼峰命名。 

  7.3 实例化bean

    传统的应用程序可以通过new关键字和反射方式进行实例化,而spring IoC容器则需要根据bean定义里的配置元数据通过反射机制来创建bean。

    。使用构造器实例化bean

  • 使用空参构造函数进行定义
1 <bean name="bean1" class="cn.javass.spring.chapter2.HelloImpl2"/>
  • 使用有参数构造函数进行定义,constructor-arg标签指定参数值,index表示参数位置,value表示常量值,也可以指定引用,指定引用使用ref来引用另一个bean定义
1 <bean name="bean2" class="cn.javass.spring.chapter2.HelloImpl2">
2    <!-- 指定构造器参数 -->
3    <constructor-arg index="0" value="Hello Spring!"/>
4 </bean>
 1 @Test
 2 public void testInstantiatingBeanByConstructor() {
 3   //使用构造器
 4   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/instantiatingBean.xml");
 5   HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);
 6   bean1.sayHello();
 7   HelloApi bean2 = beanFactory.getBean("bean2", HelloApi.class);
 8   bean2.sayHello();
 9 }    

    。使用静态工厂方式实例化bean

1 <!-- 使用静态工厂方法 -->
2 <bean id="bean3" class="cn.javass.spring.chapter2.HelloApiStaticFactory" factory-method="newInstance">
3    <constructor-arg index="0" value="Hello Spring!"/>
4 </bean>
 1 public class HelloApiStaticFactory {
 2    //工厂方法
 3   public static HelloApi newInstance(String message) {
 4     //返回需要的Bean实例
 5      return new HelloImpl2(message);
 6   }
 7 }
 8 @Test
 9 public void testInstantiatingBeanByStaticFactory() {
10   //使用静态工厂方法
11   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chaper2/instantiatingBean.xml");
12   HelloApi bean3 = beanFactory.getBean("bean3", HelloApi.class);
13   bean3.sayHello();
14 }

    。使用实例工厂方法实例化bean

1 <!—1、定义实例工厂 Bean -->
2 <bean id="beanInstanceFactory" class="cn.javass.spring.chapter2.HelloApiInstanceFactory"/>
3 <!—2、使用实例工厂 Bean 创建 Bean -->
4 <bean id="bean4" factory-bean="beanInstanceFactory" factory-method="newInstance">
5   <constructor-arg index="0" value="Hello Spring!"></constructor-arg>
6 </bean>
 1 public class HelloApiInstanceFactory {
 2   public HelloApi newInstance(String message) {
 3      return new HelloImpl2(message);
 4   }
 5 }
6
7 @Test 8 public void testInstantiatingBeanByInstanceFactory() { 9   //使用实例工厂方法 10   BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/instantiatingBean.xml"); 11   HelloApi bean4 = beanFactory.getBean("bean4", HelloApi.class); 12   bean4.sayHello(); 13 }

  通过以上例子我们发现只是配置不一样,从获取方式看完全一样没有任何不同。

  至此我们已经讲完了spring IoC容器基础部分,包括IoC容器概念,如何实例化容器,bean配置、命名及实例化,bean获取等等。

猜你喜欢

转载自www.cnblogs.com/ouhouki/p/9685693.html