spring框架(二)——spring概述與spring的核心之IOC
上面一節我們說了spring的體系和jar包的依賴關係,這節筆者主要詳解一下spring3.x
一、Spring概述
1、Spring是什麼?
Spring是分層的Java SE/EE應用 full-stack輕量級開源框架,以IoC(Inverse Of Control:反轉控制)和AOP(Aspect Oriented Programming:面向切面程式設計)為核心,提供了展現層Spring MVC和持久層Spring JDBC以及業務層事務管理等眾多的企業級應用技術,還能整合開源世界眾多著名的第三方框架和類庫,逐漸成為使用最多的Java EE企業應用開源框架。2、Spring3.X的體系結構
4、Spring帶來的好處
方便解耦,簡化開發通過Spring提供的IoC容器,可以將物件間的依賴關係交由Spring進行控制,避免硬編碼所造成的過度程式耦合。使用者也不必再為單例模式類、屬性檔案解析等這些很底層的需求編寫程式碼,可以更專注於上層的應用。
AOP程式設計的支援
通過Spring的AOP功能,方便進行面向切面的程式設計,許多不容易用傳統OOP實現的功能可以通過AOP輕鬆應付。
宣告式事務的支援
可以將我們從單調煩悶的事務管理程式碼中解脫出來,通過宣告式方式靈活的進行事務的管理,提高開發效率和質量。
方便程式的測試
可以用非容器依賴的程式設計方式進行幾乎所有的測試工作,測試不再是昂貴的操作,而是隨手可做的事情。
方便整合各種優秀框架
Spring可以降低各種框架的使用難度,提供了對各種優秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支援。
降低JavaEE API的使用難度
Spring對JavaEE API(如JDBC、JavaMail、遠端呼叫等)進行了薄薄的封裝層,使這些API的使用難度大為降低。
Java原始碼是經典學習範例
Spring的原始碼設計精妙、結構清晰、匠心獨用,處處體現著大師對Java設計模式靈活運用以及對Java技術的高深造詣。它的原始碼無意是Java技術的最佳實踐的範例。
5、Spring的資源
5.1 下載開發資源包
官方網站: http://spring.io/5.2、Spring的資源包介紹
spring Framework的官方發行包內部結構為:
5.3、關於資源包的說明
Spring Framework官方最新版本是4.3.2。但是能下載到的就是3.2,這是Spring3這個版本的最後一個官方資源包。之後的版本全用MAVEN整合了。Spring依賴的第三方資源包能下載的版本就是3.0.2。後面的也都整合到MAVEN裡面去了。
6、搭建Spring核心開發環境
6.1、拷貝最基本的核心jar包
根據第一節。新增這4個jar包以及它的依賴包(spring-Context其實還依賴了aop但是這裡因為講解IOC所以不用依賴也是可以的)。所以上圖為他們的4個jar包名稱。
6.2、核心依賴的jar包(日誌輸出)
commons-logging或log4j:用哪個都行。6.3、Spring的配置檔案:基於xml或註解的方式
(下面搭建專案時在講解)
概述部分講解完畢。下面開始spring的核心之一IOC部分
二、Spring的核心之IoC(Inversion of Control 控制反轉)
1、IoC是什麼?
注意:這裡需要理解什麼是注入。(舉例,比如普通的set方法就是一種注入等等。)
2、Spring容器
Spring容器簡單理解就是用於存放物件的一個boss那麼一個東西。3、Spring的IoC入門(注意:這裡只是IOC的入門案例,瞭解ioc是怎麼個過程)
3.1、建立一個java工程(沒有整合web專案,所以jar工程就夠用了)
3.2、匯入Spring的核心jar包(5個jar包)
3.3、建立一個XML配置檔案
注意:現在xml檔案用什麼名字無所謂。
3.4、資源交給Spring容器管理(當你寫好了controller層,service層,以及dao層時需要交給spring來管理他們的關係)
比如:寫好了dao層之後:
3.5、Spring容器的初始化及資源的獲取
配置依賴注入:service與dao層之間的關係:
在service層中寫一個register方法,呼叫dao層的方法(注入的dao中有save方法)如下:
package springIoc.service;
import springIoc.dao.XXDao1;
public class XXService1 {
private XXDao1 xxDao1;
public void setXxDao1(XXDao1 xxDao1) {
this.xxDao1 = xxDao1;
}
public void rgeister(){
xxDao1.save();
}
}
初始化和資源的獲取測試:
package springIoc.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springIoc.service.XXService1;
public class Client {
public static void main(String[] args) {
/* 注意這是直接new物件獲取,耦合度很高,沒有呼叫spring來管理的bean == 不採用
* XXService1 xxService1 = new XXService1();
xxService1.rgeister();
*/
//Spring容器的初始化
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springIoc/bean.xml");
//獲取資源
//XXDao1 xxdao1 = (XXDao1) ac.getBean("xxDao1");
//xxdao1.save();
XXService1 xxService1 = (XXService1) ac.getBean("xxService1");
xxService1.rgeister();
}
}
結果成功!
4、Spring中API的體系結構(瞭解)
4.1、核心介面和類
BeanFactory:它使用的是延遲載入思想。當我們需要用bean時,才去建立物件。ApplicationContext:它繼承自BeanFactory介面,還繼承了很多其他介面。功能比BeanFactory強大。它用的不是延遲載入思想,而是在載入配置檔案時就建立了。(推薦)
FileSystemXmlApplicationContext:配置檔案在本地磁碟上,使用該類載入。
ClassPathXmlApplicationContext :配置檔案在classpath中,使用此類載入。
特別注意:以上主要ioc已經講解完畢!下面的Ioc配置部分很重要,兩種方式在實際開發中用到的都很多!
5、基於XML的spring的IoC配置
5.1、Spring例項化bean的方式
a、呼叫預設的構造方法 (推薦)
<!-- dao層 -->
<bean id="xxDao1" class="springIoc.dao.XXDao1"></bean>
<bean id="xxDao2" class="springIoc.dao.XXDao2"></bean>
b、靜態工廠方法初始化:老系統才有可能用到(現在已經完全不用了)
c、例項工廠方法初始化:老系統才有可能用到(現在已經完全不用了)
5.2、Bean的作用範圍(Bean下的scope標籤)
* scope屬性的取值:
* singleton :預設值.單例的.Spring生成Bean的時候採用的是單例的模式.
* prototype :多例的.Spring生成Bean的時候採用的是多例的模式.每次getBean的時候都會得到一個新的Bean的例項.(與Struts2整合時要使用此值)
* request :應用在web應用中.建立一個Bean的例項將Bean例項存入到request域中.
* session :應用在web應用中.建立一個Bean的例項將Bean的例項存入session域中.
* globalsession :應用在web應用中.全域性session.一般用於Porlet應用環境.如果沒有Porlet環境.配置全域性session等價於session.
5.3、Bean的生命週期方法
init-method:Bean初始化的時候執行的方法.
destroy-method:
Bean銷燬的時候執行的方法.必須是在scope=”singleton”情況下使用.
<bean id="xxDao1" class="springIoc.dao.XXDao1" init-method="init" destroy-method="destory"></bean>
拓展:
Bean的完整的生命週期:
Spring框架管理Bean的時候,非常精確.Bean的生成過程中有11個步驟.11個步驟才構成了Bean的完整的生命週期.
1.instantiate bean物件例項化
2.populate properties 封裝屬性
3.如果Bean實現BeanNameAware 執行 setBeanName
4.如果Bean實現BeanFactoryAware 或者 ApplicationContextAware 設定工廠 setBeanFactory 或者上下文物件 setApplicationContext
5.如果存在類實現 BeanPostProcessor(後處理Bean) ,執行postProcessBeforeInitialization
6.如果Bean實現InitializingBean 執行 afterPropertiesSet
7.呼叫<bean init-method="init"> 指定初始化方法 init
8.如果存在類實現 BeanPostProcessor(處理Bean) ,執行postProcessAfterInitialization
9.執行業務處理
10.如果Bean實現 DisposableBean 執行 destroy
11.呼叫<bean destroy-method="customerDestroy"> 指定銷燬方法 customerDestroy
* 第三步和第四部為了讓Bean瞭解Spring的環境的..
* 第五步和第八部是實現了一個介面BeanPostProcessor.
注意:當非單例時,初始化方法正常執行,但是銷燬方法就不會執行了。
5.4、依賴注入(DI)
a、構造器注入(呼叫預設構造方法):通過傳引數
0 先定義一個bean類,只提供有參的構造方法(並給每個引數提供get方法,方便測試時判斷是否注入進去值)
package springIoc.bean;
import java.util.Date;
public class Bean1 {
private String name;
private int age;
private Date birthday;
//提供了有參構造方法,沒有提供預設的構造方法
public Bean1(String name, int age, Date birthday) {
super();
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Date getBirthday() {
return birthday;
}
}
1、編寫bean.xml交給spring管理這個類。
2.編寫測試類,判斷是否注入成功
package springIoc.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springIoc.bean.Bean1;
public class Client {
public static void main(String[] args) {
//Spring容器的初始化
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springIoc/bean.xml");
//獲取資源
Bean1 bean1 = (Bean1) ac.getBean("bean1");
System.out.println("姓名:"+bean1.getName()+"年齡:"+bean1.getAge()+"現在時間:"+bean1.getBirthday());
}
}
打印出:姓名:小馬同志年齡:26現在時間:Fri Oct 27 09:47:20 CST 2017
b、屬性注入:推薦(也是常用的)
0 先定義一個bean類,定義的欄位需要提供setter方法(不然注入不進去)並提供預設的構造方法(必須)
package springIoc.bean;
import java.util.Date;
public class Bean1 {
private String name;
private int age;
private Date birthday;
public Bean1() {
super();
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Date getBirthday() {
return birthday;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
1、編寫bean.xml交給spring管理這個類。
<bean id="now" class="java.util.Date"></bean>
<bean name="bean1" class="springIoc.bean.Bean1">
<!-- 屬性注入 -->
<property name="name" value="小馬"></property>
<property name="age" value="26"></property>
<property name="birthday" ref="now"></property>
</bean>
2.編寫測試類
package springIoc.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springIoc.bean.Bean1;
public class Client {
public static void main(String[] args) {
//Spring容器的初始化
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springIoc/bean.xml");
//獲取資源
Bean1 bean1 = (Bean1) ac.getBean("bean1");
System.out.println("姓名:"+bean1.getName()+"年齡:"+bean1.getAge()+"現在時間:"+bean1.getBirthday());
}
}
測試成功。
c、p名稱空間(不做細講)
d、SpEL(Spring Expression Lanaguage)
e、注入集合資料
5.5、團隊開發:多個Spring配置檔案
兩種形式:
* 載入配置檔案的時候一併引入.
* ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml", "applicationContext2.xml");
* 總的配置檔案中引入其他的配置檔案.
* <import resource="applicationContext2.xml"/>
基於xml的配置檔案就講解到這。需要會。下面說一下基於註解的配置也是同樣重要,
6、基於註解的spring的IoC配置
6.1、註解的使用前提(3個步驟必須有的!)
a、引入context的名稱空間b、指定要掃描的包
c、在Bean上面加入@Component註解
0、配置a和b的步驟
1 之後執行c在指定的類中添加註解(control層和service層以及dao層都需要新增各自的註解)(稍後會有詳細的註解介紹)
package springIoc.dao;
import org.springframework.stereotype.Component;
/**
* @Component是spring的一個註解,它是把XXDao1看做一個元件。
* 就相當於xml中 <bean id="xxDao1" class="springIoc.dao.XXDao1"></bean>
* @author mch
*
*/
@Component
public class XXDao1 {
public void save() {
System.out.println("SPRING3.XIOC成功了");
}
}
注意:@Component(value="xxDao1") 也可以寫成這種註解而value值相當於bean的id
2、編寫測試類執行結果
package springIoc.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springIoc.dao.XXDao1;
public class Client {
public static void main(String[] args) {
//Spring容器的初始化
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springIoc/springxml.xml");
//獲取資源
XXDao1 xxDao1 = (XXDao1) ac.getBean("xxDao1");
xxDao1.save();
}
}
6.2、常用註解
a、@Component作用:讓Spring容器管理當前的Bean(例項化)
屬性:
value:指定bean的名稱。預設值是當前類簡單名稱(不是全類名)首字母小寫。
b、@Component的衍生註解@Controller @Service @Repository
作用:和@Component作用一樣,讓Spring容器管理(例項化)當前的bean。
屬性: value:指定bean的名稱。預設值是當前類的簡單類名首字母小寫
特點:在三成架構中,每個註解對應一層,使語義更加明確。
@Controller:一般用在表現層,比如struts2的action上
@Service:一般用在業務層,比如Service實現
@Repository:一般用在持久層,比如Dao實現
c、@Autowired
作用:自動按型別注入需要的物件。當使用了該註解時,setter就不是必須的了。
屬性:
required:是否必須注入成功。預設值是true。
true:必須注入成功,如果出現注入失敗,丟擲異常。
false:不一定注入成功,不拋異常。
注意事項:
一個Service介面:IBookService
兩個Service實現:BookServiceImpl1 BookServiceImpl2
由於@Autowired是自動按型別注入,當使用介面型別時,就看變數的名稱,如果變數名稱是bookServiceImpl1,則使用BookServiceImp1這個實現類,
如果變數名是bookServiceImpl2,則使用BookServiceImpl2這個實現類。如果沒有符合規範的名稱(類名首字母小寫),則報錯。
到底注入哪個實現類:
@Autowried
private BookService bookServiceImpl1;//注入BookServiceImpl1
@Autowried
private BookService bookServiceImpl2;//注入BookServiceImpl2
@Autowried
private BookService bookService;//注入失敗
d、@Value
作用:注入基本型別和String。
屬性:value:SpEL表示式,要注入的值
package springIoc.dao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Component是spring的一個註解,它是把XXDao1看做一個元件。
* 就相當於xml中 <bean id="xxDao1" class="springIoc.dao.XXDao1"></bean>
* @author mch
*
*/
@Component(value="xxDao1")
public class XXDao1 {
@Value("小碼")
private String name;
public void save() {
System.out.println("SPRING3.XIOC成功了");
}
public String getName() {
return name;
}
}
提供get方法檢視是否注入成功
package springIoc.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springIoc.dao.XXDao1;
public class Client {
public static void main(String[] args) {
//Spring容器的初始化
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springIoc/springxml.xml");
//獲取資源
XXDao1 xxDao1 = (XXDao1) ac.getBean("xxDao1");
xxDao1.save();
System.out.println(xxDao1.getName());
}
}
結果為成功
e、@Qualifier
作用:要配合@Autowried來一起使用,通過它指定要注入的bean的名稱。按型別注入失效了。
屬性:value:要注入的bean的名稱
f、@Resource
作用:如同@Autowire和@Qualifier,是規範JSR-250中定義的(JCP)。通過指定bean的名稱注入物件。
屬性: name:要注入的bean的名稱
g、@PostConstruct(瞭解)
作用:用在初始化方法上。生命週期有關
h、@PreDestroy(瞭解)
作用:用在銷燬方法上。生命週期有關
i、@Configuration和@Bean(瞭解)
作用:@Configuration指定當前類為配置類,用於載入@Bean的定義。@Bean用於定義bean的名稱,用法是@Bean(name="beanName")
注意:該類要被設定在註解自動掃描對應的包下。
6.3、Spring中使用單元測試
a、匯入jar包:
spring-test-3.2.0.RELEASE.jar
b、設定Junit執行器和Spring配置檔案
步驟:
0、編寫一個類(dao層)
package springIoc.dao;
import org.springframework.stereotype.Component;
/**
* @Component是spring的一個註解,它是把XXDao1看做一個元件。
* 就相當於xml中 <bean id="xxDao1" class="springIoc.dao.XXDao1"></bean>
* @author mch
*
*/
@Component(value="xxDao1")
public class XXDao1 {
public void save() {
System.out.println("SPRING3.XIOC成功了");
}
}
1、設定是spring配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
<!-- 指定Spring要掃描的包
注意:它會掃描當前包和當前包的子包下的所有類(base-package:以點分割包名)
-->
<context:component-scan base-package="springIoc"></context:component-scan>
</beans>
2、進行編寫測試類。進行測試
package springIoc.dao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)//指定新的執行器,該執行前會初始化Spring容器,並注入資源,執行Junit單元測試
@ContextConfiguration(locations={"classpath:springIoc/springxml.xml"})//指定spring容器要載入的配置檔案
public class XXDao1Test {
@Autowired
private XXDao1 xxDao1;
@Test
public void test1(){
xxDao1.save();
}
}
結果成功!
總結:
其實spring的Ioc原理是 IOC原理:工廠 + 反射 + 配置檔案.
那麼Spring的Ioc就說到這,後面在繼續瞭解它。