Spring的基础知识——IOC与DI

一、IOC

        (1)、概念:把对象的建立、初始化、销毁等工做交给Spring来作java

        (2)、Hello Worldspring

            首先导入必须的jar包数据库

            

            接着建立bean容器配置文件applicationContext.xml(文件名可随意)编程

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	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.xsd">
	
	<!-- hello world -->
	<bean id="helloworld" class="ff.helloworld.HelloWorld"></bean>
	
</beans>

            <beans>元素中属性是一些必要的约束,<bean>元素描述某个类,id属性是bean惟一标识,class属性是类的全限定名安全

            而后建立HelloWorld类和测试类,进行测试session

public class HelloWorld {
	
	public void say() {
		System.out.println("Hello World -Spring");
	}

}

       

public class TestHelloWorld {
	
	private ApplicationContext applicationContext;
	
	@Before
	/**
	 * 加载context
	 */
	public void init() {
		
		applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
	
	@Test
	public void testSay() {
		
		HelloWorld hw = (HelloWorld) applicationContext.getBean("helloworld");
		hw.say();
	}
}

            加载配置文件applicationContext.xml生成ApplicationContext对象,再用它的getBean()方法从bean容器中获取helloworld对象,调用say()方法。
app

    (3)、Spring建立对象的三种方式
框架

        a、构造器(用的最多)
dom

            经过类的构造器建立对象,上面helloworld案例就是经过构造器建立
性能

        b、静态工厂

           applicationContext.xml中不配置具体的某个bean,而是配置一个工厂bean,在建立工厂bean的时候调用工厂方法(factory-method)建立具体bean。

<!-- 静态工厂建立bean -->
	<bean 
		id="beanDemoFactory_static" class="ff.beanCreate.BeanDemoFactory_Static" 
		factory-method="getInstance" lazy-init="true"></bean>
public class BeanDemo {
	
	public BeanDemo() {
		System.out.println("i am BeanDemo");
	}
	
	public void say() {
		System.out.println("i am created!");
	}
}
public class BeanDemoFactory_Static {
	
	public static BeanDemo getInstance() {
		
		return new BeanDemo();
	}
}

         c、实例工厂

            application中不配置具体某个bean,而是配置一个工厂bean同时配置一个第三方bean,在建立第三方bean的时候经过factory-bean属性找到工厂bean,再调用工厂方法(factory-method属性)建立具体bean。

<!-- 实例工厂建立bean -->
	<bean 
		id="beanDemoFactory_instance" class="ff.beanCreate.BeanDemoFactory_instance"></bean>
	<!-- 第三方bean -->
	<bean 
		id="beanDemo_instance" factory-bean="beanDemoFactory_instance" 
		factory-method="getInstance"></bean>
public class BeanDemo {
	
	public BeanDemo() {
		System.out.println("i am BeanDemo");
	}
	
	public void say() {
		System.out.println("i am created!");
	}
}
public class BeanDemoFactory_instance {
	
	public BeanDemo getInstance() {
		
		return new BeanDemo();
	}
}

          d、为何要用工厂方式建立对象?

            实现bean建立和使用分离,将bean建立的工做交由工厂来完成。这样能够统一管理bean的建立,如能够在各个bean建立前作一些初始化工做。此外,便于集成其它框架的bean建立管理方法。

    (4)、Spring建立对象的时机

        Spring默认在启动IoC容器时自动建立对象,但能够经过配置<bean>元素的lazy-init属性自定义建立时机。

        lazy-init属性有三种值:default、false、true。默认值为default,效果等同于值false,在启动时建立对象,若将其设置为true则在获取bean的时候建立对象。

        注意:通常不设置为true,缘由是这样设置后Spring在启动不会建立这个bean,若是这个bean有bug,那么启动时不会报错,致使存在安全隐患。若一个bean的属性中含有大量数据,过早的放入内存会影响程序性能,这时候将lazy-init设置为ture。

    (5)、bean的scope(做用域)

       a、 默认状况

            默认状况下Spring建立的bean是单例的,每次获取bean的时候返回同一个对象,这个bean的属性天然也被多处引用中共享,这样很不安全。因此默认状况下不能将数据定义到bean属性中。

        b、修改bean的scope

            <bean>元素中的scope属性能够修改scope。scope属性有四个值singleton(单例)、prototype(多例)、request、session,其中prototype为原型模式,每次获取bean返回不一样对象。

        c、选择单例仍是多例?

            Spring IoC容器在启动时会建立applicationContext.xml文件中配置的全部bean,实际开发中大多数的bean只会使用到1次,因此默认配置为单例,对特殊bean配置成多例。

    (6)、scope与建立时机的结合

        a、当scope为property时,无论lazy-init值是什么,都在获取bean的时候建立对象。由于property是多例模式,每次获取bean的时候都会返回不一样的对象。

        b、当scope为singleton时,在何时建立对象由lazy-init决定,且都以单例模式建立。

    (7)、bean初始化,销毁

        <bean>元素的init-method和destory-method定义初始化和销毁方法。

    (8)、bean建立、初始化、销毁的顺序

        当Spring启动(或代码中获取bean)时建立bean对象,接着Spring内部调用初始化方法(若是配置),当Spring容器关闭时执行这个bean对象的销毁方法。

        说明:一、初始化和销毁方法由Spring内部执行。 二、销毁方法在Spring容器关闭时执行,但Spring容器通常不会关闭,因此容器里的对象会一直存在。三、若是<bean>元素的scope属性值为property,Spring容器不负责销毁。

二、 DI(依赖注入)

        (1)、概念:给bean对象属性赋值

        (2)、三种赋值方式

            a、经过setter方法赋值

                配置<bean>元素内<property>子元素,在bean被建立时调用对应的setter方法给属性注入值。

<bean id="persion" class="domain.Persion">
		<property name="student" ref="student"></property>
		<property name="string" value="this is a string"></property>
		<property name="list">
			<list>
				<value>index1</value>
				<value>index2</value>
				<ref bean="student"/>
			</list>s
		</property>
	</bean>
public class Persion {
	
	private Student student;  // Student对象
	private String string;
	private List list;
	
	public void say(Student student) {
		student.say();
	}

	public void setStudent(Student student) {
		this.student = student;
	}

	public void setString(String string) {
		this.string = string;
	}

	public void setList(List list) {
		this.list = list;
	}
}

        当Person对象被建立时,Spring经过<property>元素找到对应的setter方法,将配置的值注入。

        <property>元素给属性注入值,value为基本类型以及String类型值,ref为引用属性的bean的id,array、list、map为集合属性

            b、经过构造方法赋值

                在<bean>元素内配置<constructor-arg>元素,当Persion类被建立时调用对应的构造器为属性赋值。

<bean id="student" class="ff.ing.pojo.Student">
		<constructor-arg index="0" value="盖伦"></constructor-arg>
	</bean>
	
	<bean id="persion" class="ff.ing.pojo.Persion">
		<constructor-arg index="0" value="007"></constructor-arg>
		<constructor-arg index="1" value="赵信"></constructor-arg>
		<constructor-arg index="2" ref="student"></constructor-arg>
	</bean>
public class Persion {
	
	private int id;
	private String name;
	private Student student;
	
	public Persion() {
		
	}
	
	public Persion(int id, String name, Student student) {
		
		this.id = id;
		this.name = name;
		this.student = student;
	}
	
	public void say() {
		String str = "id:" + id + "   name:" + name + "   student:" + student.getName();
		System.out.println(str);
	}
}

       index属性为构造器参数列表中参数的序号。    

        c、经过注解赋值

            一、依赖注入注解

          (1) 首先须要修改applicationContext.xml文件:添加注解命名空间约束,启动依赖注入注解解析器

<!-- 添加注解命名空间约束 -->
xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
		
<!-- 启动依赖注入注解解析器 -->
<context:annotation-config/>

<!-- bean -->
<bean>........</bean>

        (2) 在类中使用注解

public class Persion {
	
	private int id;
	private String name;
	
	@Resource(name="student")
	private Student student;
	
    ………
    ………
}

   @Resource会到IoC容器中寻找id与name匹配的bean,赋值给student属性。

    @Resource是java内置注解,Spring框架定义了本身的注解。@Autowired按照类型进行匹配;@Qualifier(value="xxx")按照id进行匹配,且只能与@Autowired组合使用,没法单独使用。

    注解只能注入引用类型值,没法注入基本类型、String类型以及集合类型值

    注解方式比xml配置方式效率低。   

    二、类扫描注解

    (1)、首先须要修改applicationContext.xml文件:添加注解命名空间约束,启动类扫描注解解析器,配置要扫描的包

<!-- 添加注解命名空间约束 -->
xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 启动类扫描注解解析器,配置要扫描的包 -->
<context:component-scan base-package="ff.ing.pojo"></context:component-scan>

    (2)在类中使用注解

@Component(value="student")
public class Student {
	
	private String name;
	
	public Student() {
		
	}
	……
	……
}


@Component(value="persion")
public class Persion {
	
	private int id;
	private String name;
	
	@Resource(name="student")
	private Student student;
	
	public Persion() {
		
	}
	……
	……
}

    @Component配置了这个类的在spring容器中的id,以Persion类为例@Component(value="persion")至关于<bean id="persion" class="……"></bean>

    Spring还提供了更细分的组件注解:@Repository@Service@Controller,分别表明dao层、业务层和控制层。他们的用法以及功能与@Component一致,只是方便了代码的阅读而已。

    类扫描注解方式比依赖注入注解方式效率还低。

  ● IoC、DI中的类继承问题

      当使用setter和构造器方法给属性输入值时,子类没法继承父类中属性的值,这时须要在<bean>元素中添加parent属性。使用注解不存在这样的问题

  ● IoC与DI的意义

    ● IoC与DI最生动的解释(摘抄他人)

首先想说说IoC(Inversion of Control,控制倒转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来讲,就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,咱们是如何找女友的?常见的状况是,咱们处处去看哪里有长得漂亮身材又好的mm,而后打听她们的兴趣爱好、号码………,想办法认识她们,投其所好送其所要,而后嘿嘿……这个过程是复杂深奥的,咱们必须本身设计和面对每一个环节。传统的程序开发也是如此,在一个对象中,若是要使用另外的对象,就必须获得它(本身new一个,或者从JNDI中查询一个),使用完以后还要将对象销毁(好比Connection等),对象始终会和其余的接口或类藕合起来。

那么IoC是如何作的呢?有点像经过婚介找女友,在我和女友之间引入了一个第三者:婚姻介绍所。婚介管理了不少男男女女的信息,我能够向婚介提出一个列表,告诉它我想找个什么样的女友,好比长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,而后婚介就会按照咱们的要求,提供一个mm,咱们只须要去和她谈恋爱、结婚就好了。简单明了,若是婚介给咱们的人选不符合要求,咱们就会抛出异常。整个过程再也不由我本身控制,而是有婚介这样一个相似容器的机构来控制。Spring所倡导的开发方式就是如此,全部的类都会在spring容器中登记,告诉spring你是个什么东西,你须要什么东西,而后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其余须要你的东西。全部的类的建立、销毁都由 spring来控制,也就是说控制对象生存周期的再也不是引用它的对象,而是spring。对于某个具体的对象而言,之前是它控制其余对象,如今是全部对象都被spring控制,因此这叫控制反转。若是你还不明白的话,我决定放弃。

IoC的一个重点是在系统运行中,动态的向某个对象提供它所须要的其余对象。这一点是经过DI(Dependency Injection,依赖注入)来实现的。好比对象A须要操做数据库,之前咱们老是要在A中本身编写代码来得到一个Connection对象,有了 spring咱们就只须要告诉spring,A中须要一个Connection,至于这个Connection怎么构造,什么时候构造,A不须要知道。在系统运行时,spring会在适当的时候制造一个Connection,而后像打针同样,注射到A当中,这样就完成了对各个对象之间关系的控制。A须要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3以后一个重要特征是反射(reflection),它容许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是经过反射来实现注入的。

    ● 意义

        实现了彻底面向接口编程(程序设计依赖于抽象的接口而非具体实现类),在代码中不须要关心具体是哪一个实现类在工做。

相关文章
相关标签/搜索