Spring筆記

Spring筆記

Spring基礎:屬於一個應用型框架,輕量級框架,可以說是一個大雜會,是一個大型的工廠。

Spring核心類庫:

1、spring依賴庫
  * SPRING_HOME/dist/spring.jar
  * SPRING_HOME/lib/jakarta-commons/commons-logging.jar
  * SPRING_HOME/lib/log4j/log4j-1.2.14.jar

2、拷貝spring配置文件到src下

3、拷貝log4j配置文件到src下

4、在UserManagerImpl中提供構造函數或setter方法,spring將實例化好的UserDao實現注入給我們

5、讓spring管理我們的對象創建和依賴,必須在spring配置中進行定義

6、編寫客戶端

 

IOC容器:控制反轉,控制反轉給我們的spring容器去管理,以前是我們來控制的,是我們自己來new對象等。

DI:注入技術,依賴的注入(還有一種實現控制反轉的技術實現叫依賴查找)

普通類型的注入配置:
<bean id="testBean" class="com.spring.dao.testBean">
  <property name="strValue" value="string"></property>
  <property name="intValue" value="1"></property>
  <property name="setValue">
    <set>
      <value>set1</value>
      <value>set2</value>
    </set>
  </property>
  <property name="listValue">
    <list>
      <value>list1</value>
      <value>list2></value>
    </list>
  </property>
  <property name="arrayValue">
    <list>
      <value>arry1</value>
      <value>arry2</value>
    </list>
  </property>
  <property name="mapValue">
    <map>
      <entry key="k1" value="v1"></entry>
      <entry key="k2" value="v2"></entry>
    </map>
  </property>
</bean>

什麼是屬性編輯器,作用?
    * 自定義屬性編輯器,spring配置文件中的字符串轉換成相應的對象進行注入
    spring已經有內置的屬性編輯器,我們可以根據需求自己定義屬性編輯器

    * 如何定義屬性編輯器?
        * 繼承PropertyEditorSupport類,覆寫setAsText()方法,參見:UtilDatePropertyEditor.java
        * 將屬性編輯器註冊到spring中,參見:applicationContext-editor.xml

依賴對象的注入方式,可以採用:
    * ref屬性
    * <ref>標籤
    * 內部<bean>來定義

日期類型的注入:spring不識別日期類型,需要自己系一個屬性編輯器來轉換,繼承類PropertyEditorSupport

例如:

public class UtilDatePropertyEditor extends PropertyEditorSupport {
private String format;

public String getFormat() {
return format;
}

public void setFormat(String format) {
this.format = format;
}

@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date date = sdf.parse(text);
this.setValue(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}

<!--內部<bean>來定義-->
<bean id="CustomEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date">
                <bean class="com.spring.util.UtilDatePropertyEditor">
                    <property name="format" value="yyyy-MM-dd"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>

<!-- 也可以如下的寫法
<bean id="CustomEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date" value-ref="UtilDatePropertyEditor"/>
        </map>
    </property>
</bean>

<bean id="UtilDatePropertyEditor" class="com.spring.util.UtilDatePropertyEditor">
    <property name="format" value="yyyy-MM-dd"/>
</bean>
-->

如何將公共的注入定義描述出來?
    * 通過<bean>標籤定義公共的屬性,指定
abstract=true
    * 具有相同屬性的類在<bean>標籤中指定其
parent屬性

    參見:applicationContext-other.xml

<!-- 公共屬性的配置 -->
<bean id="BeanAbstruct" abstract="true">
    <property name="id" value="100"/>
    <property name="name" value="zhangshan"/>
</bean>

<!-- 使用parent屬性來制定公共屬性 -->
<bean id="bean3" parent="BeanAbstruct" class="com.spring.dao.Bean3">
    <!-- 也可以覆蓋繼承來的公共屬性 -->
    <property name="name" value="lisi"/>
    <property name="pwd" value="123"></property>
</bean>
<bean id="bean4" parent="BeanAbstruct" class="com.spring.dao.Bean4"></bean>

 

Bean的作用域

當多次使用BeanFactory。getBean()的時候,當get同一個bean的時候,他們的應用時相等的(默認是相等的),但是可以改變:
<!-- bean id="testBean" scope="prototype" class="com.spring.dao.testBean" -->
<bean id="testBean" scope="singleton" class="com.spring.dao.testBean">
scope可以取值:
  * singleton:每次調用getBean的時候返回相同的實例
  * prototype:每次調用getBean的時候返回不同的實例

 

Spring的裝配方式

*根據名稱自動裝配 default-autowire="byName"
*根據類型自動裝配 default-autowire="byType"

 

AOP:提供了聲明式服務。提供代理服務。

靜態代理:

      比如對UserManager的安全性檢查(UserManager的每個方法都要先進行安全檢查),

代理類必須要與原類實現同樣的接口,即有共同的接口,它的缺點是,代理類的每個方法都必須加一個安全性檢查,安全性檢查散步在代理類裏了。

IOC管理對象,但是AOP不管對象,只管橫切性的東西拿出來,在運行時加進去。

基於jdk的動態代理:

    基於靜態代理的缺點,如我除了安全性檢查,還想加一個日子呢,這樣導致代理類的每個方法都要去更改了。

public class SecurityHandler implements InvocationHandler{

//目標對象
private Object targetObject;

//創建代理類
public Object newProxy(Object obj) {
   this.targetObject = obj;
   return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
            targetObject.getClass().getInterfaces(),
            this);
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   checkSecurity();
   Object ret = null;
   try {
      ret = method.invoke(this.targetObject, args);
   } catch(Exception e) {
      e.printStackTrace();
   }
   return ret;
}

public void checkSecurity() {
System.out.println("checkSecurity()");
}
}

test:

public class Client {
   public static void main(String[]args) {
      SecurityHandler handler = new SecurityHandler();
      UserManager usermanager =(UserManager) handler.newProxy(new       UserManagerImpl());

      usermanager.addUser("zhu", "123");
   }
}

注意:也可以配置,當方法(Method)是delete的時候,才做安全性檢查。method.getName()可以獲取當前調用的方法名稱。

橫切性的問題,它會散步在代碼的各個角落,如安全性檢查,我們叫橫切性關注點(Cross cutting concern),advice(橫切點的實現)()Before Advice 、after advice,橫切類(如剛剛的SecurityHandler類),JoinPoint(連接點,spring只支持方法的連接點),Weave(植入,把切面應用到目標對象上的這樣的一個過程叫植入)

Spring對AOP的支持方式:

(採用Annotation的方式)

1、spring依賴庫
* SPRING_HOME/dist/spring.jar
* SPRING_HOME/lib/jakarta-commons/commons-logging.jar
* SPRING_HOME/lib/log4j/log4j-1.2.14.jar
* SPRING_HOME/lib/aspectj/*.jar

2、採用Aspect定義切面

3、在Aspect定義Pointcut和Advice

4、啓用AspectJ對Annotation的支持並且將Aspect類和目標對象配置到Ioc容器中

<aop:aspectj-autoproxy/>

注意:在這種方法定義中,切入點的方法是不被執行的,它存在的目的僅僅是爲了重用切入點
即Advice中通過方法名引用這個切人點

AOP:
* Cross cutting concern
* Aspect
* Advice
* Pointcut
* Joinpoint
* Weave
* Target Object
* Proxy
* Introduction

/**
* 定義Aspect
* @author Administrator
*
*/
@Aspect
public class SecurityHandler {

   /**
   * 定義Pointcut,Pointcut的名稱就是allAddMethod,此方法不能有返回值和參數,該方法只是一個
   * 標識
   *
   * Pointcut的內容是一個表達式,描述那些對象的那些方法(訂閱Joinpoint)
   */
   @Pointcut("execution(* add*(..)) || execution(* del*(..))")
   private void allAddMethod(){};

      /**
      * 定義Advice,標識在那個切入點何處織入此方法
      */
   @Before("allAddMethod()")
   private void checkSecurity() {
      System.out.println("----------checkSecurity()---------------");
   }

}

spring對AOP的只是(採用配置文件的方式)

1、spring依賴庫
* SPRING_HOME/dist/spring.jar
* SPRING_HOME/lib/jakarta-commons/commons-logging.jar
* SPRING_HOME/lib/log4j/log4j-1.2.14.jar
* SPRING_HOME/lib/aspectj/*.jar

2、配置如下
<aop:config>
   <aop:aspect id="security" ref="securityHandler">
      <aop:pointcut id="allAddMethod" expression="execution(* com.bjsxt.spring.UserManagerImpl.add*(..))"/>
      <aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
   </aop:aspect>
</aop:config>

spring對AOP的支持

Aspect默認情況下不用實現接口,但對於目標對象(UserManagerImpl.java),在默認情況下必須實現接口
如果沒有實現接口必須引入CGLIB庫

我們可以通過Advice中添加一個JoinPoint參數,這個值會由spring自動傳入,從JoinPoint中可以取得
參數值、方法名等等

1、如果目標對象實現了接口,默認情況下會採用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

如何強制使用CGLIB實現AOP?
* 添加CGLIB庫,SPRING_HOME/cglib/*.jar
* 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK動態代理和CGLIB字節碼生成的區別?
* JDK動態代理只能對實現了接口的類生成代理,而不能針對類
* CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
因爲是繼承,所以該類或方法最好不要聲明成final

採用編程式事務

1、getCurrentSession()與openSession()的區別?
   * 採用getCurrentSession()創建的session會綁定到當前線程中,而採用openSession()
創建的session則不會
   * 採用getCurrentSession()創建的session在commit或rollback時會自動關閉,而採用openSession()
創建的session必須手動關閉

2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
   * 如果使用的是本地事務(jdbc事務)
   <property name="hibernate.current_session_context_class">thread</property>
   * 如果使用的是全局事務(jta事務)
   <property name="hibernate.current_session_context_class">jta</property>

 

採用聲明式事務

1、聲明式事務配置
* 配置SessionFactory
* 配置事務管理器
* 事務的傳播特性
* 那些類那些方法使用事務

2、編寫業務邏輯方法
* 繼承HibernateDaoSupport類,使用HibernateTemplate來持久化,HibernateTemplate是
Hibernate Session的輕量級封裝
* 默認情況下運行期異常纔會回滾(包括繼承了RuntimeException子類),普通異常是不會滾的
* 編寫業務邏輯方法時,最好將異常一直向上拋出,在表示層(struts)處理
* 關於事務邊界的設置,通常設置到業務層,不要添加到Dao上

3、瞭解事務的幾種傳播特性
1. PROPAGATION_REQUIRED: 如果存在一個事務,則支持當前事務。如果沒有事務則開啓
2. PROPAGATION_SUPPORTS: 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行
3. PROPAGATION_MANDATORY: 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。
4. PROPAGATION_REQUIRES_NEW: 總是開啓一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。
5. PROPAGATION_NOT_SUPPORTED: 總是非事務地執行,並掛起任何存在的事務。
6. PROPAGATION_NEVER: 總是非事務地執行,如果存在一個活動事務,則拋出異常
7. PROPAGATION_NESTED:如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務,
則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行

4、Spring事務的隔離級別
1. ISOLATION_DEFAULT: 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.
另外四個與JDBC的隔離級別相對應
2. ISOLATION_READ_UNCOMMITTED: 這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的數據。
這種隔離級別會產生髒讀,不可重複讀和幻像讀。
3. ISOLATION_READ_COMMITTED: 保證一個事務修改的數據提交後才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據
4. ISOLATION_REPEATABLE_READ: 這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。
它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重複讀)。
5. ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理爲順序執行。
除了防止髒讀,不可重複讀外,還避免了幻像讀。

 



spring+struts的集成(第一種集成方案):缺點,在action中要取得beanfactory,必然依賴了beanfactory。


原理:在Action中取得BeanFactory對象,然後通過BeanFactory獲取業務邏輯對象

1、spring和struts依賴庫配置
  * 配置struts
    --拷貝struts類庫和jstl類庫
    --修改web.xml文件來配置ActionServlet
    --提供struts-config.xml文件
    --提供國際化資源文件
  * 配置spring
    --拷貝spring類庫
    --提供spring配置文件

2、在struts的Action中調用如下代碼取得BeanFactory
BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());

需要配置listener及參數:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext-*.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

3、通過BeanFactory取得業務對象,調用業務邏輯方法

 

spring+struts的集成(第二種集成方案)

原理:將業務邏輯對象通過spring注入到Action中,從而避免了在Action類中的直接代碼查詢

1、spring和struts依賴庫配置
  * 配置struts
    --拷貝struts類庫和jstl類庫
    --修改web.xml文件來配置ActionServlet
    --提供struts-config.xml文件
    --提供國際化資源文件
  * 配置spring
    --拷貝spring類庫
    --提供spring配置文件
2、因爲Action需要調用業務邏輯方法,所以需要在Action中提供setter方法,讓spring將業務邏輯對象注入過來

3、在struts-config.xml文件中配置Action
  * <action>標籤中的type屬性需要修改爲org.springframework.web.struts.DelegatingActionProxy
DelegatingActionProxy是一個Action,主要作用是取得BeanFactory,然後根據<action>中的path屬性值
到IoC容器中取得本次請求對應的Action

4、在spring配置文件中需要定義struts的Action,如:
<bean name="/login" class="com.bjsxt.usermgr.actions.LoginAction" scope="prototype">
<property name="userManager" ref="userManager"/>
</bean>
  * 必須使用name屬性,name屬性值必須和struts-config.xml文件中<action>標籤的path屬性值一致
  * 必須注入業務邏輯對象
  * 建議將scope設置爲prototype,這樣就避免了struts Action的線程安全問題

Struts + Spring + Hibernate集成

基本配置:ApplicationContext-common.xml:

<!--配置Hibernate的SessionFactory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
   <property name="configLocation">classpath:hibernate.hcf.xml</property>
</bean>

<!--配置事物管理器-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTranscationManager">
   <property name="sessionFactory">
        <ref bean="sessionFactory"/>
   </property>
</bean>

<!-- 配置事務的傳播特性 -->
<tx:advice id="txAdvice" transcation-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="del*" propagation="REQUIRED"/>
        <tx:method name="modify*" propagation="REQUIRED"/>
        <tx:method name="*" read-only="true"/>
    </tx:attributes>
</tx:advice>

<!--哪些類的那些方法參與事物-->
<aop:config>
     <aop:pointcut id="allManagerMethod" expression="execution(* xxx.xxx.*.*(..))"/>
     <aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/>
</aop:config>

在web.xml中加入相應的配置:

配置spring的bean配置文件
<context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>classpath*:applicationContext-*.xml</param-value>
</context-param>

配置LoaderListern:
<listener>
     <listener-class>
          org.springframework.web.context.ContextLoaderListener
     </listener-class>
</listener>

配置spring提供的字符轉換filter:
<filter>
     <filter-name>springCharacterEncoding</filter-name>
     <filter-class>
          org.springframework.web.filter.CharacterEncodingFilter
     </filter-class>
     <init-param>
          <param-name>encoding</param-name>
          <param-value>utf-8</param-value>
     </init-param>
</filter>
<filter-mapping>
     <filter-name>springCharacterEncoding</filter-name>
     <url-pattern>/*</url-pattern>
</filter-mapping>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章