Spring——(二)IOC控制反转/DI依赖注入

2018-10-24 08:26:00     

一、理解IOC和DI

  1. IOC(即控制反转)它不是什么技术,而是一种设计思想。
  • 传统创建对象的方式是通过new关键字,而Spring则是通过IOC容器来创建对象。IOC让程序员不在关注怎么去创建对象,而是关注与对象创建之后的操作,把对象的创建、初始化、销毁等工作交给Spring容器来做。
  • IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:别找我们,我们找你即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找
  • 通常情况下,我们在家喝果汁,首先要买水果,买果汁机,然后自己榨成果汁,整个过程复杂且繁琐。如果去饮料店喝果汁呢?只需要告诉饮料店我需要什么果汁,果汁的创建过程等工作交给饮料店来做,至于果汁是怎么做的我不管,我只需要喝到果汁就行,当果汁有问题时,我们就向饮料店抛出异常。此时饮料店扮演的角色就是Spring IOC容器
  • DI(依赖注入)
  • 比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢?Java 1.3之后一个重要特征是反射reflection,它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring`就是通过反射来实现注入的。

二、Spring常用的三种注入方式

  • setter注入
  • 构造方法注入
  • 基于注解的注入(不了解)

三、setter注入

  • service包下新建一个Teacher实体类,再创建一个Student实体类,在Student类中引入Teacher对象
	package service;

	public class Teacher {
		private int age;
		private String name;

		public int getAge() {
			return age;
		}

		public void setAge(int age) {
			this.age = age;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

	}

	package service;
	
	public class Student {
		private int id;
		private String name;
		private Teacher teacher;
	
		public Teacher getTeacher() {
			return teacher;
		}
	
		public void setTeacher(Teacher teacher) {
			this.teacher = teacher;
		}
	
		public int getId() {
			return id;
		}
	
		public void setId(int id) {
			this.id = id;
		}
	
		public String getName() {
			return name;
		}
	
		public void setName(String name) {
			this.name = name;
		}
	
	}
  • 编辑Spring Bean文件我这边是application-config.xml通过XML文件配置的方式装配我们的bean
	<?xml version="1.0" encoding="UTF-8"?>
	
	<beans xmlns="http://www.springframework.org/schema/beans" 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		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">
			
		<!-- bean标签中的name属性自定义(name不是一个必需的属性,id属性也可以定义 bean 元素的名称) -->	
	    <bean name="student" class="service.Student">
	    	<!-- 注入value值到name属性中 -->
	    	<property name="id" value="21"></property>
	    	<property name="name" value="Bounds"></property>
	    	<!-- 使用 ref 属性注入下面配置bean标签中name属性为teacher的teacher对象  -->
	    	<property name="teacher"><ref bean="teacher"/></property>
	    </bean>
	    <bean name="teacher" class="service.Teacher">
	    	<!-- 注入value值到name属性中 -->
	    	<property name="age" value="63"></property>
	    	<property name="name" value="Cubi"></property>
	    </bean>
	    
	</beans>

  • 在test包下新建一个TestSpring测试类,此类我们使用Junit单元测试
	package test;
	
	import org.junit.Test;
	import org.springframework.context.ApplicationContext;
	import org.springframework.context.support.ClassPathXmlApplicationContext;
	
	import service.Student;
	
	public class TestSpring {
		@Test
		public void TestService() {
			// 从资源文件启动Spring Ioc容器并做初始化
			ApplicationContext context = new ClassPathXmlApplicationContext(
					new String[] { "spring/application-config.xml" });
			// 创建Spring Ioc容器对象,按照名字和类型拿 bean
			Student s = (Student) context.getBean("student");
			// 通过对象获取数据
			System.out.println(s.getId() + ",,," + s.getName());
			System.out.println(s.getTeacher().getAge() + ",,," + s.getTeacher().getName());
			// 销毁Spring容器
			((ClassPathXmlApplicationContext) context).close();
	
		}
	}

  • 打印出的信息,结果如下:
 21,,,Bounds   
 63,,,Cubi 

四、构造方法注入

  • Teacher实体类修改为:
	package service;
	
	public class Teacher {
		private int age;
		private String name;
	
		public int getAge() {
			return age;
		}
	
		public void setAge(int age) {
			this.age = age;
		}
	
		public Teacher(int age, String name) {
			super();
			this.age = age;
			this.name = name;
		}
	
		public String getName() {
			return name;
		}
	
		public void setName(String name) {
			this.name = name;
		}
	
	}

  • Student实体类修改为:
	package service;
	
	public class Student {
		private int id;
		private String name;
		private Teacher teacher;
	
		public Teacher getTeacher() {
			return teacher;
		}
	
		public void setTeacher(Teacher teacher) {
			this.teacher = teacher;
		}
	
		public int getId() {
			return id;
		}
	
		public void setId(int id) {
			this.id = id;
		}
	
		public String getName() {
			return name;
		}
	
		public void setName(String name) {
			this.name = name;
		}
	
		public Student(int id, String name, Teacher teacher) {
			super();
			this.id = id;
			this.name = name;
			this.teacher = teacher;
		}
	
	}

  • Spring 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"
		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">
			
		<!-- bean标签中的name属性自定义(name不是一个必需的属性,id属性也可以定义 bean 元素的名称)-->	
	  <!--   <bean name="student" class="service.Student">
	    	注入value值到name属性中
	    	<property name="id" value="21"></property>
	    	<property name="name" value="Bounds"></property>
	    	使用 ref 属性注入下面配置bean标签中name属性为teacher的teacher对象
	    	<property name="teacher"><ref bean="teacher"/></property>
	    </bean>
	    <bean name="teacher" class="service.Teacher">
	    	注入value值到name属性中
	    	<property name="age" value="63"></property>
	    	<property name="name" value="Cubi"></property>
	    </bean> -->
	    
	    <bean name="student" class="service.Student">
	    	<!-- 通过index下标(下标从零开始)以及类型确定构造函数里边的参数 -->
	    	<constructor-arg index="0" type="int" value="18"></constructor-arg>
	    	<!-- 使用 ref 属性注入下面配置bean标签中name属性为teacher的Teacher对象 -->
	    	<constructor-arg index="2" type="Teacher" ref="teacher"></constructor-arg>
	    	<constructor-arg index="1" type="String" value="Bounds"></constructor-arg>
	    </bean>
	    <bean name="teacher" class="service.Teacher">
	    	<constructor-arg index="0" type="int" value="63"></constructor-arg>
	    	<constructor-arg index="1" type="String" value="Cubi"></constructor-arg>
	    </bean>
	    
	</beans>

  • 打印出的结果是不变的

五、引入其他配置文件

在实际开发中,随着应用程序规模的增加,系统中bean元素配置的数量也会大大增加,导致 application-config.xml配置文件变得非常臃肿难以维护

  • application-config.xml使用import元素引入其他配置文件即可
  • 新建Spring xml文件,取名为bean.xml
  • bean.xml中装配Teacher实体类
	<?xml version="1.0" encoding="UTF-8"?>
	
	<beans xmlns="http://www.springframework.org/schema/beans" 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		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">
			
		<!-- bean标签中的name属性自定义(name不是一个必需的属性,id属性也可以定义 bean 元素的名称) -->	
	    <bean name="teacher" class="service.Teacher">
	    	<!-- 注入value值到name属性中 -->
	    	<property name="age" value="63"></property>
	    	<property name="name" value="Cubi"></property>
	    </bean>
	    
	</beans>

  • application-config.xml中装配Student实体类,并且使用import元素引入,注意:<import resource="bean.xml" />需放在bean配置的最前面
	<?xml version="1.0" encoding="UTF-8"?>
	
	<beans xmlns="http://www.springframework.org/schema/beans" 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		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">
        <!-- 引入bean.xml文件 -->
		<import resource="bean.xml" />
		<!-- bean标签中的name属性自定义(name不是一个必需的属性,id属性也可以定义 bean 元素的名称) -->	
	    <bean name="student" class="service.Student">
	    	<!-- 注入value值到name属性中 -->
	    	<property name="id" value="21"></property>
	    	<property name="name" value="Bounds"></property>
	    	<!-- 使用 ref 属性注入下面配置bean标签中name属性为teacher的teacher对象  -->
	    	<property name="teacher"><ref bean="teacher"/></property>
	    </bean>

	</beans>

六、总结

  • 如果spring的配置文件中的bean中没有<constructor-arg>该元素,则调用默认的构造函数
  • 如果spring的配置文件中的bean中有<constructor-arg>该元素,则该元素确定唯一的构造函数
  • 在过去的开发过程中,这两种注入方式都是非常常用的。Spring也同时支持两种依赖注入方式:setter注入和构造注入。 这两种依赖注入的方式,并没有绝对的好坏,只是适应的场景有所不同
  • 测试类中的ApplicationContext的作用?

ps:本篇博客源码下载链接:https://pan.baidu.com/s/1xovvSWxh9WZcfPjOHkDnrg 密码:morl
Spring——(一)配置搭建

一、认识Spring框架Spring 框架是 Java 应用最广的轻量级框架,它的成功来源于理念,而不是技术本身。它的理念包括 IoC (Inversion of Control,控制反转) 和 AOP(Aspect Oriented Programming,面向切面编程)。Spring 的根本使命就是简化 Java 开发。二、Spring下载与安装为了写这篇博客,把之前装好的Spring干掉了重新安装,然后花了将近4个小时也没能再装上。网上查找了各种偏方也无能为力,真心快要崩溃了...无奈只能卸载Eclipse,删除了所有的相关配置文件。最终装了个最新版本的Eclipse才搞定——(Spring3版本与JDK1.8版本不兼容,说多了都是泪)安装Spring有两种方式第一种通过本地压缩包方式安装,这里给出地址:第一种安装方式第二种通过Eclipse自带的商店安装,这里给出地址:第二种安装方式三、搭建Spring+Web+Maven项目打开Eclipse——File——Other——Spring——Spring Legacy Project填上项目名,再选择Simple

Spring——(三)生命周期

一、摘要Spring容器生命周期BeanFactory类ApplicationContext类二、Spring生命周期1.创建SpringTest02工程,在service包下新建HelloSpring类,如下代码: package service; public class HelloSpring { public HelloSpring() { System.out.println("构造方法。。。"); } // 定义初始化方法 public void init() { System.out.println("init..."); } public void hello() { System.out.println("hello..."); } // 定义销毁方法 public void destory() { System.out.println("destory..."); } } 2.配置application-config.xml文件,代码如下: <?xml version="1.0" encoding=

 发表评论