Spring使用之IOC
這一段純屬廢話,可以不用看........,兌現諾言,每週寫一篇部落格。最近除了學習演算法,還有想更全面瞭解Spring框架的使用。於是開始了我的學習之旅。由於本人工作中接觸的是一個非常非常老的專案,所以對Spring的瞭解僅僅停留在一些基本的使用上。為加深瞭解Spring提供的功能,於是就果斷買了《Spring實戰》,初略看下來,收穫還是有的,但總感覺也不是特別特別優秀的書。接下來,我就來談談我對Spring的一點淺薄理解。
一、Spring第一印象
對於Java後端開發來說,Spring基本是再熟悉不過的框架了,甚至可以說,現在不用Spring框架進行開發的JAVA後端專案應該基本是鳳毛麟角(個人猜測)。相信一提到Spring,大家想到的就是DI(Dependency Injection)/IOC(Inversion of Control)、AOP這些名詞了,沒錯,這就是Spring提供的核心功能。DI、IOC說的就是同一個功能,翻譯過來分別是依賴注入、控制反轉,其實就是我們把物件的建立、銷燬、維護交給Spring,讓它幫我們管理這些物件,但我們需要的時候,讓它直接給我們一個,不需要我們自己去new。AOP就是面向切面程式設計。額額,看著這些名詞一臉懵逼.................................
接下來就來個小例子看看這到底能幹嘛,能給我們程式設計提供什麼樣的幫助。。
在給小例子之前我們得先了解兩個概念:
1、既然要讓Spring幫我們建立管理物件、那我們就得先告訴Spring怎麼去建立這些物件,還有物件之間是什麼關係。Spring提供了3個方案來實現:1、XML中顯式配置。2、Java中顯式配置。3、自動包掃描
2、Spring提供了倆種容器型別,分別為BeanFactory、ApplicationContext。BeanFactory只提供了基本的DI支援,ApplicationContext基於BeanFactory構建,能提供更多服務。
Spring上下文,就是一種容器,繼承自ApplicationContext,提供更多功能,如常見的,
AnnotationConfigApplicationContext可從JAVA配置類中載入上下文
ClassPathXmlApplicationContext 從類路徑下的XML檔案中載入上下文。
FileSystemXmlApplilcationContext 從檔案系統路徑中載入上下文
例子
接下來我們用Idea編輯器,通過maven工具建立一個maven專案來體驗下Spring。建立完之後我們首先要引入Spring jar包,通過maven,我們不需要自己去下載,只需要在配置檔案中配置我們需要用到的jar包。專案結構如下圖
之後我們在pom.xml檔案中配置需要用到的jar檔案,我們將spring的幾個核心包配置進來。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.springstudy</groupId>
<artifactId>luckyspring</artifactId>
<version>1.0-SNAPSHOT</version>
<name>luckyspring</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<!-- spring 版本 -->
<org.springframework.version>4.0.0.RELEASE</org.springframework.version>
</properties>
<dependencies>
<!-- 當前專案用到的3個核心spring jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
複製程式碼
現在假設我們有一個公司,一個公司裡面得有僱員來工作,才能讓公司提供服務,於是我們建立僱員類
package cn.springstudy.vo;
public class Employee {
public void work(){
System.out.println("Employ start to Work");
};
}複製程式碼
再建立公司類
package cn.springstudy.vo;
public class Company {
//公司類有個僱員物件
private Employee employee;
public void supportService(){
employee.work();
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}複製程式碼
前面我們說過告訴Spring怎麼去建立物件有三種方式
方式一XML配置來告訴spring怎麼去建立我們的僱員還有公司類,在建立一個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">
<!-- 配置一個物件 指定該物件id為emplayee-->
<bean id="employee" class="cn.springstudy.vo.Employee"></bean>
<!--配置物件,之後往物件中放入一個Employee物件
ref="employee"表示注入的物件為spring容器中id為employee的物件,這樣配置後建立Company
物件後,會自動呼叫setEmployee()方法放入一個Employee物件
-->
<bean id="company" class="cn.springstudy.vo.Company">
<property name="employee" ref="employee"></property>
</bean>
</beans>複製程式碼
接下來我們建立一個main函式作為程式的入口,在main函式中去建立Spring容器
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringStudy {
public static void main(String arg[]){
//方式一,XML檔案中載入上下文,即Spring容器
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//從容器中獲取一個Company物件
Company company = (Company) classPathXmlApplicationContext.getBean("company");
company.supportService();
}
}複製程式碼
執行一下,控制檯列印如下
我們可以看到我們執行company.supportService()居然沒報空指標,要知道我們可沒在Company類中去建立Empoyee物件,說明什麼???Spring容器自動幫我們建立Employee物件並set到Company物件中了。
方式二
建立一個配置Java類
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import cn.springstudy.vo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//註解,表明這個是一個Spring配置類
@Configuration
public class SpringConfig {
//Spring容器管理的類,通過Bean註解,方法名即預設為bean的id,也可在Bean註解後加引數指定Bean的ID
@Bean
public Employee employee(){
return new Employee();
}
//Spring容器管理的類,通過Bean註解
@Bean
public Company company(){
Company company = new Company();
company.setEmployee(employee());
return company;
}
}
複製程式碼
main函式,程式入口,執行結果同上
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringStudy {
public static void main(String arg[]){
//方式二,預設bean的名稱即為配置方法的名稱,需要用到AnnotationConfigApplicationContext容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(SpringConfig.class);
annotationConfigApplicationContext.refresh();
Company company1 = (Company) annotationConfigApplicationContext.getBean("company");
company1.supportService();
}
}複製程式碼
方式三、
方式三序藉助方式一或者方式二,我們首先需要在需要被Spring容器管理的類上面加上@Component註解,所以我們在Empoyee加上註解
package cn.springstudy.vo;
import org.springframework.stereotype.Component;
@Component
public class Employee {
public void work(){
System.out.println("Employ start to Work");
};
}複製程式碼
Company類上加上註解,需自動分配的物件上加@Autowired註解
package cn.springstudy.vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Company {
//Autowired,幫我分配個Employee物件過來。
@Autowired
private Employee employee;
public void supportService(){
employee.work();
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}複製程式碼
在配置類上加上包自動掃描路徑
package cn.springstudy.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//cn.springstudy.vo 為掃描的基礎包路徑
@Configuration
@ComponentScan("cn.springstudy.vo")
public class SpringConfigScan {
}複製程式碼
測試main方法
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringStudy {
public static void main(String arg[]){
//方式三,需藉助方式2
AnnotationConfigApplicationContext annotationConfigApplicationContext2 = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext2.register(SpringConfig.class);
annotationConfigApplicationContext2.refresh();
Company company2 = (Company) annotationConfigApplicationContext.getBean("company");
company2.supportService();
}
}複製程式碼
執行結果同上。
XML、Java配置檔案混著使用
當然XML配置方式和Java配置檔案還能混著用。
1、在XML配置中混用Java配置檔案只需在配置檔案中增加一個<bean></bea>即可將Java配置類匯入XML配置中。2、XML中匯入其他XML配置,只需用<import>指定其他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">
<!--匯入其他XML配置檔案 -->
<import resource="applicationContext2.xml"></import>
<!--Spring Java配置類-->
<bean class="cn.springstudy.spring.SpringConfig"></bean>
<bean id="employee" class="cn.springstudy.vo.Employee"></bean>
<bean id="company" class="cn.springstudy.vo.Company">
<property name="employee" ref="employee"></property>
</bean>
</beans>複製程式碼
1、Java配置檔案混著XML配置檔案,只需在Java類中加個註解即可,2、Java配置類匯入其他配置類,只需加@Import註解,指定配置類位置。
package cn.springstudy.spring;
import cn.springstudy.vo.Company;
import cn.springstudy.vo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
//匯入其他XML配置檔案
@ImportResource("classpath:applicationContext.xml")
//匯入其他配置類
@Import({SpringConfigScan.class})
public class SpringConfig {
@Bean
public Employee employee(){
return new Employee();
}
@Bean
public Company company(){
Company company = new Company();
company.setEmployee(employee());
return company;
}
}複製程式碼
Spring DI初步使用方法已經如上,接下來我們主要通過XML配置的方式來說明其他功能。
構造方法注入依賴物件
以上的小例子中Company中的Employee物件是通過setEmployee方法配置進去的。我們還可以通過構造方法的形式配置進去。
給Company類增加一個構造方法
package cn.springstudy.vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
public class Company {
private Employee employee;
private String name;
public Company(Employee employee,String name){
this.employee = employee;
this.name = name;
}
public void supportService(){
employee.work();
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}複製程式碼
配置檔案配置如下
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/c
http://www.springframework.org/schema/c/spring-c.xsd">
<!--在上面beans中宣告spring中c名稱空間-->
<bean id="employee" class="cn.springstudy.vo.Employee"></bean>
<!-- 構造方法中注入Employee物件,還有一個名稱其中
c:為名稱空間字首
emplayee、name分別為建構函式中引數的名稱
-ref表示注入的是spring容器中的物件
"emplayee"表示引入的是id為emplayee的物件,name沒有帶-ref則是注入字串juejin.com
-->
<bean id="company" class="cn.springstudy.vo.Company"
c:employee-ref="employee"
c:name="juejin.com">
</bean>
</beans>複製程式碼
工廠方法模式建立物件
以上說明Spring的依賴注入的基本使用。我們在程式設計時候可能不是通過new來建立物件,有時也會使用靜態方法(靜態工廠模式)來建立物件,那麼Spring是否支援呢?答案是肯定的。
public class ClientService {
private ClientService() {}
public static ClientService createInstance() {
return new ClientService()
}
}複製程式碼
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>複製程式碼
當然工廠方法模式是通過非通過靜態方法建立物件的,Spring也是支援的,如下
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}複製程式碼
<!-- 工廠類 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean>
<!-- ClientService類配置 -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>複製程式碼
Spring中bean的作用域
預設情況下,Spring容器中的bean都是單例的,可以通過配置修改。spring定義了多種作用域:
1、Singleton(預設) 單例
2、Prototype 原型,每次通過容器獲取物件都會建立一個新物件、
3、Session 會話,一個web會話中使用一個物件
4、Request ,每次web請求使用一個物件
通過XML配置可在bean中指定scrop屬性指定,
Java配置類可在方法上加註解@Scope("prototype")
自動掃描的類可在類上加註解@Scope("prototype")
<!-- scope 屬性指定作用域 -->
<bean id="employee" class="cn.springstudy.vo.Employee" scope="prototype"></bean>複製程式碼
@Component
@Scope("prototype")
public class Company {.....}複製程式碼
@Configuration
public class SpringConfig {
@Bean
@Scope("prototype")
public Employee employee(){
return new Employee();
}
}複製程式碼
最後,感覺這篇寫得有點亂,也很基礎,還有很多東西沒說到,不知道看到這裡的人兒有無收穫,說好的一週一篇,額,那就先發出來吧,以後可能還做修改,待續。。