1. 課程回顧 1-1
1.1. Spring 概述 1-1
1.2. Spring IOC 概述 1-2
1.3. Spring IOC 程式設計 1-2
2. Spring Bean依賴 2-2
2.1.1. 依賴注入基礎 2-2
2.1.2. 依賴注入進階 2-2
2.1.3. 依賴值的自動裝配 2-5
3. Spring 註解應用 3-6
3.1. Spring 註解概述 3-6
3.2. Spring 註解基本應用 3-6
3.2.1. 常用註解說明 3-6
3.2.2. 註解應用案例 3-7
3.2.3. 配置註解掃描 3-7
3.2.4. 編寫測試類獲取bean 3-8
3.3. Spring 註解應用增強 3-8
3.3.1. 作用域及生命週期 3-8
3.3.2. 延遲載入配置 3-8
3.3.3. 自動裝配配置 3-9
4. 總結 4-9
4.1. 重點和難點分析 4-9
4.2. 常見FAQ 4-9
1. 課程回顧
1.1. Spring 概述
- Spring 是什麼?(框架,半成品)
- Spring 能解決什麼問題(物件導向,面向切面,面向服務)
- Spring 框架核心?(IOC,AOP,MVC,…)
個人認為:Spring 最強大是它的資源整合能力。
1.2. Spring IOC 概述
- IOC是什麼?(控制反轉:由spring構建物件,管理物件依賴)
- IOC 應用優勢?(解耦,更好的管理物件,使用系統資源)
- IOC 的核心?(工廠,配置,依賴注入)
- IOC 程式設計步驟?(類,配置,獲取)
1.3. Spring IOC 程式設計
- Spring Bean物件初始化,作用域,宣告週期,延遲載入
1) Bean型別的編寫(修飾符,構造方法)
2) Bean 的配置(applicationContext.xml)
3) Bean 的作用域(singleton,prototype)
4) Bean 的生命週期(生命週期方法的使用)
5) Bean 的延遲載入(區域性lazy-init,全域性 default-lazy-init)
- Spring Bean依賴(依賴注入,自動裝配)
1) 依賴注入(DI)的定義(通過spring為類中的屬性注入值)
2) 依賴注入的實現(set注入,構造注入)
3) 依賴注入中的集合值的注入(陣列,list,set,map)
4) 依賴注入中的自動裝配(未講)
2. Spring Bean依賴
2.0.1. 依賴注入基礎
重點了解set,構造注入的方式以及單個值如何實現注入。
2.0.2. 依賴注入進階
重點了解集合型別值的注入,例如list,hashmap,properties等
案例1:
定義一個相對複雜的物件
public class ComplexObject {
private String[] names;
private List<String> address;
private Map<String,Integer> map;
private Properties properties;
//set,get
}
在配置檔案中配置此物件,併為屬性注入值
<?xml version="1.0" encoding="UTF-8"?> <beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <bean id="cObj" class="beans.ComplexObject"> <!-- 為String[]陣列屬性注入值 --> <property name="names"> <list> <!-- #{}為spring中的一個表示式 --> <value>name-1</value> <value>name-2</value> </list> </property> <!-- 為list<String>集合注入值 --> <property name="address"> <list> <value>北京</value> <value>深圳</value> <value>上海</value> </list> </property> <!-- 為map屬性注入值 --> <property name="map"> <map> <entry key="k1" value="200"/> <entry key="k2" value="300"/> </map> </property> <!-- 為properties屬性注入值 --> <property name="properties"> <props> <prop key="pk1">pv1</prop> <prop key="pk2">pv2</prop> </props> </property> </bean> </beans>
案例2:spring配置檔案中引入properties檔案中的資料
step1:類路徑的根目錄定義properties檔案cfg.properties,其內容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=root
step2:在spring配置檔案中引入此配置檔案(藉助util標籤)
<util:properties id="cfg" location="classpath:cfg.properties"/>
step3:在Bean物件中引入配置檔案中的值
<bean id="dataSource" class="beans.DataSource">
<property name="driver" value="#{cfg.driver}"/>
<property name="url" value="#{cfg.url}"/>
<property name="username" value="#{cfg.username}"/>
<property name="password" value="#{cfg.password}"/>
</bean>
其中#{}為spring中一個表示式,通過這個表示式可以獲取properties檔案中的值
例如#{cfg.driver}為獲取id為cfg對應的物件中key為driver的值。
2.0.3. 依賴值的自動裝配
Spring中為bean物件中的屬性提供了自動裝配功能,此功能的開啟需要藉助bean標籤中的autowire屬性進行指定,此屬性的值預設有如下幾個:
NO |
自動配置(預設) |
|
ByName |
按名字自動裝配(重點掌握) |
|
ByType |
按型別自動狀態(重點掌握),但有多個型別時會出錯 |
|
Constructor |
與byType類似,不同之處在於它應用於構造器引數。 |
例如:
定義並配置DataSource物件
public class DataSource {
}
<bean id="dataSource" class="beans.DataSource"/>
定義並配置JdbcTemplate物件
public class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate() {}
public JdbcTemplate(DataSource dataSource) {
this.dataSource=dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
<bean id="jdbcTemplate" class="beans.JdbcTemplate" autowire="constructor"> </bean>
自動裝配應用總結
v byName 按屬性對應的set方法名從容器中查詢名字相同的bean,然後進行注入。假如出現了名字相同,但型別不同的Bean物件時,會注入失敗
v byType 先從容器中查詢屬性型別相匹配的值然後找按類中對應的set方法(看引數型別),最後通過set方法為物件的屬性注入值。假如容器中出現多個型別相同的物件,就會注入失敗。
v constructor 先從容器中查詢屬性型別相匹配的值,然後找類中對應的構造方法(看引數型別)最後通過構造方法為物件的屬性注入值。假如容器中出現多個型別相同的物件,此時再比對引數名字,假如有同名的則直接注入,沒有同名的就會注入失敗。
3. Spring 註解應用
3.1. Spring 註解概述
Spring中提供了兩種方式對Bean進行描述,一種是基於xml方式,一種是基於註解方式。基於註解方式主要是依託於註解對bean以及bean中的屬性進行描述
然後spring底層通過反射獲取bean上定義的這些註解,通過註解描述初始化物件,管理物件的作用域以及物件與物件之間的依賴。
3.2. Spring 註解基本應用
3.2.1. 常用註解說明
元件應用註解
|
註解名 |
說明 |
@Component |
通用註解 |
|
@Repository |
持久層元件應用註解 |
|
@Service |
業務層元件應用註解 |
|
@Controller |
控制層元件應用註解 |
3.2.2. 註解應用案例
資料層物件
@Repository
業務層物件
@Service
控制層物件
@Controller
3.2.3. 配置註解掃描
Spring中通過指定一個包路徑,由系統自動掃描該包及其子包所有元件類,當發現元件類定義前有特定的註解標記時,就將該元件納入到Spring容器。
例如:用元件掃描,首先需要在XML配置中指定掃描父級package路徑,例如
<context:component-scan base-package=”com.company.spring/>”
在這個配置中,容器會自動掃描org.example包及其子包下所有元件,並例項化bean物件。
3.2.4. 編寫測試類獲取bean
3.3. Spring 註解應用增強
3.3.1. 作用域及生命週期
@Scope("singleton") @Repository public class SysUserDao { /**@PostConstruct註解修飾方法在物件初始化時執行*/ @PostConstruct public void init(){ System.out.println("init"); } public void insertObject(){ System.out.println("insertObject"); } /**@PreDestroy物件銷燬時執行*/ @PreDestroy public void destory(){ System.out.println("destory"); } }
3.3.2. 延遲載入配置
@Lazy(false) @Service public class SysUserService { }
3.3.3. 自動裝配配置
註解方式的自動裝配一般會藉助@Autowired和@Resource實現,具體過程參考
註解自動裝配使用說明:
應用位置
1)@Autowired/@Qualifier 一般用於修飾屬性和構造方法
2)@Resource 一般用於修飾屬性和set方法
注入規則:
1)@Autowired 修飾屬性,構造方法,set方法時預設按照屬性型別或引數型別進行值的注入。假如容器中有多個型別相同的Bean,此時還會按名字進行匹配,沒有相匹配的則注入失敗。假如希望按名字進行匹配需要再此基礎加上@Qualifier註解。
2)@Resource 修飾屬性,set方法時預設按屬性名或set方法名進行匹配,假如Resource指定了名稱則按指定名稱進行匹配,假如沒有找到相匹配的名稱,則按型別進行值的注入。
1. Spring 註解工廠應用剖析
1.1. Bean工廠是用於做什麼的?
所有的工廠都是用於建立物件的,物件建立一般會基於某中策略對物件進行儲存。
例如Spring 中的Bean工廠:ApplicationContext
1) ClassPathXmlApplicationContext
2) AnnotationApplicationContext
3) …….
1.2. Bean工廠的實現的基本原理?
Spring 中所有的Bean假如需要由Spring管理,此時需要以xml描述的方式或註解的描述方式告訴spring容器。Spring底層內建了對xml的解析,通過反射獲取註解描述,然後基於這些描述通過反射構建物件。
1.3. Bean工廠理解的拔高?
手寫基於註解方式的Spring Bean工廠
1) 包的掃描(將包轉換為類所在的路徑,然後進行檔案的查詢)
2) 構建類全名(包名+類名,例如java.util.Date)
3) 基於反射構建類的物件(獲取Class物件,構建構造方法物件,構建類的例項物件)
4) 儲存類的物件(key是誰)
5) 需要時從工廠中獲取bean物件即可
1.4. Bean 工廠手寫應用實踐
1.4.1. 註解定義實現
定義一個用於修飾bean,描述bean的註解。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
定義一個用於描述配置的註解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
}
1.4.2. 定義Bean元件
定義一個IdGenerator類,然後使用@Component註解修飾
@Component
public class IdGenerator {}
1.4.3. 定義Bean工廠
這個Bean工廠要實現的功能是基於配置類上的@ComponentScan註解,對註解中定義包進行類的掃描,然後構建類的物件,再將物件儲存到map集合,需要時從map獲取。其程式碼如下:
public class AnnotationAppContext{ private Map<String,Object> beanMap= new HashMap<String,Object>(); public AnnotationAppContext(Class<?> c)throws Exception{ //1.獲取class(例如AppConfig)上的@ComponentScan註解 ComponentScan cs=c.getAnnotation(ComponentScan.class); //2.獲取註解中定義的包名 String pkg=cs.value(); //替換包名中的“.”,改成目錄結構 String dir=pkg.replaceAll("\\.", "/"); //3.基於包獲取包對應的類路徑 URL url= getClass().getClassLoader() .getResource(dir); System.out.println("url="+url); //4.獲取類路徑下所有的class檔案(例如IdGenerator) File pkgDir=new File(url.getPath()); //4.1獲取目錄下所有class檔案 File[] fs=pkgDir.listFiles();//class //4.2遍歷所有檔案,構建類全名 for(File f:fs){ String fname= f.getName().substring(0,f.getName().lastIndexOf(".")); String clsName=pkg+"."+fname; Class<?> cls=Class.forName(clsName); //5.基於class檔案上註解(@Component)描述構建類物件 if(!cls.isAnnotationPresent(Component.class)) continue; Object obj=newInstance(cls); //6.將類物件儲存到map集合 //6.1獲取key的值 Component cp=cls.getAnnotation(Component.class); String key=cp.value(); if("".equals(key)){ key=String.valueOf( fname.charAt(0)).toLowerCase()+ fname.substring(1); } //6.2儲存到map beanMap.put(key, obj); } } private Object newInstance(Class<?> cls) throws Exception{ Constructor<?> c= cls.getDeclaredConstructor(); c.setAccessible(true); return c.newInstance(); } public Object getBean(String beanName){ return beanMap.get(beanName); } @SuppressWarnings("unchecked") public <T>T getBean(String beanName, Class<T> cls){ return (T) beanMap.get(beanName); } public static void main(String[] args) throws Exception{ AnnotationAppContext ctx= new AnnotationAppContext(AppConfig.class); IdGenerator obj1=(IdGenerator) ctx.getBean("idGenerator"); IdGenerator obj2= ctx.getBean("idGenerator",IdGenerator.class); System.out.println(obj1); System.out.println(obj2==obj1); } }
2. 總結
2.1. 重點和難點分析
|
2.2. 常見FAQ
|
2.3. 作業
- 總結spring註解應用
- 嘗試手寫spring bean 工廠