從三層架構到Spring框架


首先是軟件的應用分層架構
  標准三層架構:
    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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM