首先是軟件的應用分層架構
標准三層架構:
1:數據訪問層:實現了數據的持久化
2:業務邏輯層:對邏輯的實現及處理,實際上不可能在表示層對數據不做任何處理,但是盡可能的將邏輯分為一層
3:表示層:數據的展示
優點:
降低了一個程序的耦合度,一個類中有一千行代碼可以轉化為三個類中各寫300多行代碼,每個類實現自己的功能
慢慢的就形成了一種標准化趨勢,更加的適應於面向接口編程,注重《開閉原則》的實現,對修改關閉,而對擴展開放,
擴展的功能定義為接口,程序員進行實現,在現有的代碼中組合進新功能的實現類對象,從而實現新功能的添加。
缺點:
然而這種三層體系架構依舊存在一些問題
1.有些時候將簡單的問題復雜化,假如:
一個類300代碼可以完成的工作,分為三層架構后每個類需要120行代碼進行完成,反而得不償失了
2.組合的代碼不一定有效,例如:
有這樣一個類:
public class A{ private IB b=new BImpl(); public void go(){ b.go(); } public static void main(String agrs[]){ new A().go(); } }
這個例子可以看出,一旦IB接口的實現類BImpl出現了問題,那么b.go()可能空指針異常,A類中的方法就無法正常運行
那么:有沒有一種方法可以不使用組合的方式來獲得對象?
Java中創建對象對象除了new關鍵字之外,有的就是反射機制了。有效的破壞莫不失為一種好想法,有了反射我們就可以直接通過權限定名來創建對象。
Spring框架的相關概念
輕量級:spring是一種輕量級框架,用戶可以自定義自己需要的內容,選擇自己需要的功能模塊
容器的概念:
Java開發中常見的容器有:GUI,Tomcat都是一些容器,比如jsp動態頁面的展示,就是需要Tomcat容器的支持才可以運行。spring框架中的容器可以管理項目中各種對象的生命周期(對象的創建、初始化、使用、銷毀)
前提是項目中要使用spring框架,並且把這些需要管理的對象配置給spring的容器,常見的IOC容器可以控制bean對象的
但是這個bean對象一般都是單例的。
生成生命周期,當然前提是對象不可以脫離容器控制范圍(單例對象和多例對象)
spring框架給項目帶來的好處:
1)動態解藕,方便開發,面向接口設計
我們可以將對象之間的依賴關系交由Spring進行控制
2)方便程序的測試
spring框架也提供了測試模塊,可以和很多主流的測試框架相結合
3)降低Java EE API的使用難度
Spring封裝了如jdbc等許多有難度的操作,使得代碼“相對”精簡。
這里的相對是說,使用了框架相當於在項目中已經引入了代碼,所以說Java之所以有許多人用,那是因為Java的類庫太豐富了
Spring功能足夠強大,但是又可以自己選擇模塊,這就十分人性化了。
但是Java在程序的效率方面來說是比不上C和C++了。
4)方便集成各種優秀框架
Spring不排斥各種優秀的開源框架,相反,Spring可以降低各種框架的使用難度
Spring提供了對各種優秀框架(如Struts,Hibernate,MyBatis)等的直接支持
5)AOP編程的支持
通過Spring提供的AOP功能,方便進行面向切面的編程
6)聲明式事務的支持
在Spring中,我們可以從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活地進行事務的管理,提高開發效率和質量
7)spring是一個模塊化的項目,可以根據自己的需要定制功能模塊
spring的核心宗旨:簡化企業級應用開發,同時給復雜問題提供強大的、非侵入性解決方案
Spring核心功能模塊 Spring Framework
在Spring Framework中又分為許多的模塊
Spring Context(spring的上下文)
Spring Web
Spring DAO
Spring ORM
Spring AOP(面向切面編程)
Spring MVC(Spring WebMVC)
Spring Core(spring的核心容器)
這個容器是Spring的一個核心容器
我當前主要學習了的是spring Core和spring AOP,也就是spring框架所提供的ioc和aop功能
Spring MVC是一個集成化的web開發框架,不恰當的說它的地位甚至可以將其從Spring中分離出來,作為一個單獨的框架
spring中的IOC
IOC:Inversion of Control 控制反轉
spring核心容器也可以稱為IOC容器,該容器主要負責管理各種對象的生命周期(對象的創建、初始化、銷毀等)
IOC容器並沒有實現更多的功能,但它的存在使我們不需要很多代碼、不需要考慮對象間復雜的耦合關系就能從IOC容器中獲取合適的對象
而且提供了各種對象的可靠的管理,極大地降低了開發的復雜性。
思考1:是什么東西的"控制"被"反轉"了?
簡單的說:是對象被控制了起來,創建對象的操作反轉給了框架
思考2:自己組裝電腦和直接購買整機的區別
DI:Dependency Injection 依賴注入
DI的概念的提出是用來代替IOC的,表示讓調用類對某一接口實現類的依賴關系由容器注入,以移除調用類對某一接口實現類的依賴。(思考servlet和service層接口以及service層接口實現類這三者的關系)
依賴注入 這個名詞顯然比 控制反轉 更直接明了,並且易於理解。
DL:Dependency Loopup 依賴查找
容器創建對象並提供 回調接口和上下文環境 給這個對象,需要時通過接口從容器中查找其他對象
(之后會見到很多XxxxAware的接口,先簡單理解即可)
Spring IOC容器核心api(容器將來會是一個對象)
BeanFactory接口
BeanFactory是Spring中IOC容器的核心接口,主要用於處理Bean的初始化和配置,建立對象間的依賴關系
接口中主要方法如下:
//根據指定名稱返回一個Bean實例
Object getBean(String name)
//判斷名稱為name的Bean是否是原型,即是否總是返回一個新實例(非單例)
boolean isPrototype(String name)
//判斷名稱為name的Bean是否是單例
boolean isSingleton(String name)
//判斷容器中是否包含給定名稱的Bean實例
boolean containsBean(String name)
//如果名稱為name的Bean有別名則返回所有別名
String[] getAliases(String name)
ApplicationContext接口
該接口繼承於BeanFactory,增強了BeanFactory,增加了事務處理AOP,國際化,事件傳遞等功能
所以在代碼中我們一般會使用ApplicationContext接口,以及這個接口相應的實現類來創建spring的容器對象
例如:
String path = "com/briup/ioc/set/set.xml";
ApplicationContext container =
new ClassPathXmlApplicationContext(path);
Student s = (Student)container.getBean("student");
//使用s即可
三層關系如下:
BeanFactory
↑
ApplicationContext
↑
ClassPathXmlApplicationContext
配置文件
這是一個框架中必不可少的部分,會寫Spring的XML文件一定會用Spring框架,但是會用不一定明白為什么這么用......
Spring通過讀取配置文件中的數據來對項目各個對象進行實例化,配置以及組裝,通常使用XML文件來作為配置文件
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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> ...... </beans>
IOC的相關功能
IOC實際上就是實現的Spring容器幫助我們管理對象的功能,所以要先從如何將對象注入到容器中來學習
注入有兩種方式:set注入和構造器注入,自動注入和繼承也屬於這個知識點內
set方式注入(必須依靠set方法)
顧名思義,實現set方式的注入就必須存在set方法
這種動態代理的方式創建對象是反射機制,如果是set注入就必須要無參構造器的支持
可以注入的內容有:
1基本類型(8中基本類型+字符串)的裝配
2對象類型的裝配
3集合的裝配
1.基本類型的裝配
方式: 配置元素<value/>
例子:
public class HelloBean { private String name; private int age; public String sayHello(){ return "hello "+name +",your age is" + age; } ............. }
配置文件set.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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <bean id="helloBean" class="ioc.HelloBean"> <property name="name"> <value>tom</value> </property> <property name="age" value="20"> </property> </bean> </beans>
id是Bean的唯一標識,要求在整個配置文件中要唯一
也可使用name屬性,bean標簽里面的id和name屬性都可以用來標識這個配置的對象
但是id會幫我們檢查給對象起的名字是否規范(名字不能重復、不能用數字開頭、不能有空格等等)
如果檢查出來了那么就會報錯name屬性不會幫檢查這些東西
property 對於所有用set方式來注入的必須使用該標簽
value 是對於基本類型,都用value(標簽/屬性)來注入,可以實現自動的數據類型轉換
這里的自動數據類型不是絕對的,自定義的類型不可以自動的數據類型轉換
如果有這方面的要求,就需要實現一個類型處理器。
測試類:
main: ApplicationContext ac = new ClassPathXmlApplicationContext("set.xml"); //獲取容器的一個實例 HelloBean hb = (HelloBean) ac.getBean("helloBean"); System.out.println(hb.sayHello());
2.對象類型的裝配
1.<ref local=" "/> 用於涉及的對象的id在本配置文件中
2.<ref bean=" "/> 用於涉及的對象的id不在本配置文件中
3.使用property的ref屬性引用,這樣就不需要處理涉及到的對象在不在同一個xml配置文件中
例如:
public class OtherBean { private String str1; public String getStr1() { return str1; } public void setStr1(String str1) { this.str1 = str1; } public String toString(){ return "OtherBean "+str1; } }
public class SomeBean { private OtherBean ob; public void printInfo(){ System.out.println("someBean "+ob); } public OtherBean getOb() { return ob; } public void setOb(OtherBean ob) { this.ob = ob; } }
配置applicationContext.xml
<bean id="someBean" class="ioc.SomeBean"> <property name="ob"> <!-- <ref bean=" "/> 用於涉及的對象的id不在本配置文件中 --> <ref bean="otherBean" /> </property> </bean>
配置other.xml文件
<bean id="otherBean" class="ioc.OtherBean"> <property name="str1"> <value>hello</value> </property> </bean>
測試類:
main: String[] path = {"ioc/applicationContext.xml","ioc/other.xml"}; ApplicationContext ac = new ClassPathXmlApplicationContext(path); SomeBean sb = (SomeBean) ac.getBean("someBean"); sb.printInfo();
3.集合的裝配
方式:配置元素<list> <set> <map> <props>
例如:
public class SomeBean { private List listProperty; private Set setProperty; private Map mapProperty; private Properties<String,String> property; get/set...... toString(); }
applicationContext.xml的寫法:
<bean id="someBean" class="ioc.SomeBean"> <property name="listProperty"> <list> <value>list1</value> <value>list2</value> <value>list3</value> </list> </property> <property name="setProperty"> <set> <value>set1</value> <value>set2</value> <value>set3</value> </set> </property> <property name="mapProperty"> <map> <entry key="key1"> <value>value1</value> </entry> <entry key="key2"> <value>value2</value> </entry> </map> </property> <property name="property"> <props> <prop key="key1">prop1</prop> <prop key="key2">prop2</prop> <prop key="key3">prop3</prop> </props> </property> </bean>
測試類:
main: String path = "ioc/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(path); SomeBean sb = (SomeBean) ac.getBean("someBean"); sb.printInfo();
基於構造器注入
方式: 配置<constructor-arg>元素
在Bean中不用寫set方法,但是要有相應的構造器
構造器注入有倆種形式 一個是根據參數類型 一個是根據參數位置的下標
<constructor-arg type="int" value="">
<constructor-arg index="0" value="">
例如:
<bean name="student" class="com.briup.bean.Student"> <constructor-arg type="int" value="25"> </constructor-arg> <constructor-arg type="java.lang.String" value="tom"> </constructor-arg> <constructor-arg type="long" value="100"> </constructor-arg> </bean>
或者:
<bean name="student" class="com.briup.bean.Student"> <constructor-arg index="2"> <value>30</value> </constructor-arg> <constructor-arg index="0"> <value>200</value> </constructor-arg> <constructor-arg index="1"> <value>lily</value> </constructor-arg> </bean>
構造器注入有倆種形式 一個是根據參數類型 一個是根據參數位置的下標
還有指定參數傳參 這里的name指的是形參的參數名字
<bean name="student" class="com.briup.bean.Student"> <constructor-arg index="0" value="2" name="a"></constructor-arg> <constructor-arg index="1" value="3" name="b"></constructor-arg> <constructor-arg index="2" value="4" name="c"></constructor-arg> </bean>
自動注入 :容器依照一些規則去裝配bean中的一個屬性
注意:自動裝配只對[對象類型]起作用,對基本類型不起作用.
第一種情況:
在beans標簽中配置裝載方式:default-autowire="byName"
在根元素beans中加入這個屬性,那么下面所有的bean都會
使用byName的方式進行自動注入,如果在下面的某一個bean
里面想使用其他的方式進行注入,可以用autowire=""屬性進行
說明,或者某一個bean不想使用任何自動注入就使用autowire="no"
第二種情況:
在bean標簽中指定配置方式
autowire="byName":
spring容器會到當前的類中找property的名字,然后
再根據這個名字去spring容器中找有沒有和這個property
名字相同的對象,有的話,就把這個對象當做參數放到
setXxxx這個方法里面注入進來.
比如Teacher類中有一個屬性Student student
對應的有setStudent()方法
在xml中配置了Student這個類。
name="studnet";
Spring在自動注入Teacher類中的student屬性的時候就會去找和這個property
名字相同的對象
<bean name="t" class="com.briup.bean.Teacher" autowire="byName">
<property name="id" value="10"></property>
<property name="name" value="王老師"></property>
<!-- <property name="student" ref="stu"></property> -->
</bean>
注意:了解property指的類中的什么東西
property來源於attribute
property name="xxxx"實際上就是setXxxx()
這四個xxxx是一個含義
autowire="byType":
spring容器會根據當前類中的set方法里面參數的類型,
去容器中找相匹配的對象,如果沒找到就算了,如果找到
一個就注入進來,如果找到多個,那么就會報錯了.
也就是說找不到大不了就賦值為null,但是找到兩個框架報錯了,因為框架不知道用哪個啊
所以說要么就不寫,寫了就不要有歧義。
autowire="constructor"
根據構造器的參數類型去匹配
繼承
配置文件中,一個bean的配置可以繼承另一個bean的配置
bean標簽中的倆個屬性:
abstract屬性
<bean name=".." class=".." abstract="true">
注:bean中一旦定義為了abstract="true",則說明該bean是用來被繼承的,不能通過該bean獲得對象了
parent屬性,指定繼承哪個bean的配置
<bean name=".." parent="另一個bean的名字">
例子:
<bean name="student" class="com.briup.bean.Student"> <property name="name"> <value>zhangsan</value> </property> </bean>
abstract="true" 表示當前的配置是一個抽象的配置,
這時候我們在代碼中就不能通過這個bean的名字teacher來
獲得相應的對象了(和java中的抽象類不能直接new對象的道理一樣)
但是我們可以再寫一個配置去繼承這個抽象的配置,當然即使當前
這個配置不是抽象的,也能夠被繼承(和java中繼承一樣)
<bean name="teacher" class="com.briup.bean.Teacher" abstract="true"> <property name="student" ref="student"></property> </bean>
parent="teacher" 表示當前配置是繼承了另外一個名字叫
teacher的bean的配置,配置和配置的繼承像java中的類和類
直接的繼承一樣,子類會把父類中的對象繼承過來.
當然在子配置里面依然是可以覆蓋父配置中已經寫的配置信息.
<bean name="t" parent="teacher"> <property name="id"> <value>11</value> </property> <property name="name"> <value>TeacherWang</value> </property> </bean>