IOC(Inverse of Control)反轉控制的概念,就是將本來在程序中手動建立對象的控制權,交由Spring框架管理。當某個Java對象(調用者)須要調用另外一個Java對象(被調用者)時,在傳統編程模式下,調用者一般會採用「new 被調用者」的代碼方式來建立對象。這種方式會增長調用者與被調用者之間的耦合性,不利於後期代碼的升級與維護。
當Spring框架出現後,對象的實例再也不由調用者來建立,而是由Spring容器來建立。Spring容器會負責控制程序之間的關係,而不是由調用者的程序代碼直接控制。這樣,控制權由調用者轉移到Spring容器,控制權發生了反轉,這就是Spring的控制反轉。java
實現控制反轉的是Spring IOC容器,Spring IOC容器的設計主要是基於Bean Factory和ApplicationContext兩個接口。web
BeanFactory由org.springframework.beans.factory.BeanFactory接口定義,它提供了完整的IOC服務支持,是一個管理Bean的工廠,主要負責初始化各類Bean。
BeanFactory接口最經常使用的實現類是org.springframework.beans.factory.xml.XMLBeanFactory,該類會根據XML配置文件中的定義來裝配Bean。
BeanFactory實例建立代碼以下:spring
@Test public void demo(){ FileSystemResource file = new FileSystemResource("C:\\demo\\applicationContext.xml"); BeanFactory beanFactory = new XmlBeanFactory(file); TestDao testDao = (TestDao) beanFactory.getBean("testDao"); testDao.sayHello(); }
因爲使用BeanFactory實例加載Spring配置文件在實際開發中並很少見,因此對於該接口僅瞭解便可。express
ApplicationContext是BeanFactory的子接口,也稱爲應用上下文,由org.springframework.context.ApplicationContext接口定義。ApplicationContext接口除了包含BeanFactory的全部功能之外,還添加了對國際化、資源訪問、事件傳播等內容的支持。
建立ApplicationContext接口實例一般有如下3中方法:編程
下面對這3種方法的代碼作演示:服務器
(1)ClassPathXmlApplicationContextapp
使用ClassPathXmlApplicationContext將從類路徑目錄(src根目錄)中尋找指定的XML配置文件,代碼示例:框架
@Test public void demo(){ //初始化Spring容器ApplicationContext,加載配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //經過容器獲取testDao實例 TestDao testDao = (TestDao) application.getBean("testDao"); testDao.sayHello(); }
(2)FileSystemXmlApplicationContextide
使用FileSystemXmlApplicationContext將從指定文件的絕對路徑中尋找XML配置文件,找到並裝載完成ApplicationContext的實例化工做,代碼示例:測試
@Test public void demo(){ ApplicationContext application = new FileSystemXmlApplicationContext("C:\\demo\\applicationContext.xml"); TestDao testDao = (TestDao) application.getBean("testDao"); testDao.sayHello(); }
(3)使用Web服務器實例化
經過Web服務器實例化ApplicationContext容器,通常使用org.springframework.web.context.ContextLoaderListener的實現方式,須要添加Spring-web依賴,pom.xml配置以下:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.2.RELEASE</version> </dependency>
在web.xml中配置代碼以下:
<context-param> <!--加載src目錄下的applicationContext.xml文件--> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--指定以ContextLoaderListener方式啓動Spring容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
經過web.xml配置,web容器會自動加載context-param中的配置文件初始化ApplicationContext實例,而後就能夠在web應用中經過WebApplicationContextUtils.getWebApplicationContext方法獲取ApplicationContext的引用,Servlet中的代碼以下:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws javax.servlet.ServletException, IOException { ApplicationContext application = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext()); TestDao testDao = (TestDao) application.getBean("testDao"); testDao.sayHello(); }
DI (Dependency Injection)依賴注入的概念,在Spring中實現IOC容器的方法是依賴注入,依賴注入的做用是在使用Spring框架建立對象時動態地將其所依賴的對象(屬性值)注入Bean組件中。
Spring框架的依賴注入一般有如下幾種實現方式:
建立User類
package test; public class User { private String name; private int age; public User(String name,int age){ this.name = name; this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
在applicationContext.xml文件中配置user實例
<?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"> <!--使用構造方法注入--> <bean id="user" class="test.User"> <constructor-arg name="name" value="張三"></constructor-arg> <constructor-arg name="age" value="20"></constructor-arg> </bean> </beans>
在測試方法中代碼
@Test public void demo(){ //初始化Spring容器ApplicationContext,加載配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //經過容器獲取實例 User user = (User) application.getBean("user"); System.out.println(user); }
運行結果
建立Course課程類
package entity; public class Course { private String cname; public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname='" + cname + '\'' + '}'; } }
建立Student學生類
package entity; public class Student { private String name; private int age; private Course course; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", course=" + course + '}'; } //getter和setter方法 }
配置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"> <!--使用set方法注入--> <bean id="course" class="entity.Course"> <property name="cname" value="大學語文"></property> </bean> <bean id="student" class="entity.Student"> <property name="name" value="張三"></property> <property name="age" value="20"></property> <property name="course" ref="course"></property> </bean> </beans>
測試方法
@Test public void demo(){ //初始化Spring容器ApplicationContext,加載配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //經過容器獲取實例 Student student = (Student) application.getBean("student"); System.out.println(student); }
運行結果
建立Course課程類
package entity; public class Course { private String cname; public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname='" + cname + '\'' + '}'; } }
建立Student學生類
package entity; public class Student { private String name; private int age; private Course course; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", course=" + course + '}'; } //getter和setter方法 }
配置applicationContext.xml文件,要在約束裏面加入p名稱空間的約束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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"> <!--使用p名稱空間注入--> <bean id="course" class="entity.Course" p:cname="英語"></bean> <bean id="student" class="entity.Student" p:name="張三" p:age="20" p:course-ref="course"></bean> </beans>
測試方法
@Test public void demo(){ //初始化Spring容器ApplicationContext,加載配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //經過容器獲取實例 Student student = (Student) application.getBean("student"); System.out.println(student); }
運行結果
咱們可使用SpEL(Spring expression language)Spring表達式語言,對依賴注入進行簡化。
語法:#{表達式},例如 <bean id="" value="#{表達式}">
#{'hello'}:使用字符串
#{beanId}:使用另外一個bean
#{beanId.content.toUpperCase()}:使用指定名屬性,並使用方法
#{T(java.lang.Math).PI}:使用靜態字段或方法
建立Course課程類
package entity; public class Course { private String cname; public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname='" + cname + '\'' + '}'; } }
建立Student學生類
package entity; public class Student { private String name; private int age; private Course course; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", course=" + course + '}'; } //getter和setter方法 }
配置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"> <!--使用SpEL方式注入--> <bean id="course" class="entity.Course"> <property name="cname" value="#{'高數'}"></property> </bean> <bean id="student" class="entity.Student"> <property name="name" value="#{'小明'}"></property> <property name="age" value="#{10}"></property> <property name="course" value="#{course}"></property> </bean> </beans>
測試方法
@Test public void demo(){ //初始化Spring容器ApplicationContext,加載配置文件 ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml"); //經過容器獲取實例 Student student = (Student) application.getBean("student"); System.out.println(student); }
運行結果
在使用SpEL時,配置中也能夠調用方法,示例代碼以下:
建立獲取年齡的類
package entity; public class GetAge { public int createAge(){ return 20; } }
配置applicationContext.xml
<!--使用SpEL方式注入--> <bean id="course" class="entity.Course"> <property name="cname" value="#{'高數'}"></property> </bean> <bean id="getAge" class="entity.GetAge"></bean> <bean id="student" class="entity.Student"> <property name="name" value="#{'小明'}"></property> <property name="age" value="#{getAge.createAge()}"></property> <property name="course" value="#{course}"></property> </bean>
執行測試方法,運行結果以下: