Spring總結-2

總結要點

Spring的三種注入方式

Spring使用注入方式,爲什麼使用注入方式,這系列問題實際歸結起來就是一句話,Spring的注入和IoC(本人關於IoC的闡述)反轉控制是一回事。下面我們詳細來了解一下
AD:
1. 接口注入(不推薦)
2. getter,setter方式注入(比較常用)
3. 構造器注入(死的應用)
關於getter和setter方式的注入

autowire="defualt" 
autowire=“byName”  
autowire="bytype"  

例如:有如下兩個類需要注入
第一個類:

package org.jia;  

  public class Order {  
      private String orderNum;  
      @SuppressWarnings("unused")  
      private OrderItem orderitem;  

      public OrderItem getOrderitem() {  
          return orderitem;  
     }  

     public void setOrderitem(OrderItem orderitem) {  
         this.orderitem = orderitem;  
     }  

     public String getOrderNum() {  
         return orderNum;  
     }  

     public void setOrderNum(String orderNum) {  
         this.orderNum = orderNum;  
     }       
 }

第二個類:

package org.jia;  

 public class OrderItem {  
     private String orderdec;  

     public String getOrderdec() {  
         return orderdec;  
     }  

     public void setOrderdec(String orderdec) {  
         this.orderdec = orderdec;  
     }  
 }

常用getter&&setter方式介紹
方式第一種注入:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 

<beans> 
    <bean id="orderItem" class="org.jia.OrderItem"> 
        <property name="orderdec" value="item00001"></property> 
    </bean> 
    <bean id="order" class="org.jia.Order" > 
        <!-----注入變量 名字必須與類中的名字一樣-------> 
        <property name="orderNum" value="order000007"></property> 
         <!--注入對象 名字爲orderitem,所屬的類的應用idorderItem--> 
        <property name="orderitem" ref="orderItem"></property> 

    --></bean> 
</beans>

方式第二種注入:byName

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
<beans>  
    <!--此時的id就必須與Order.java中所定義的OrderItem的對象名稱一樣了,不然就會找不到-->  
    <bean id="orderitem" class="org.jia.OrderItem">  
        <property name="orderdec" value="item00001"></property>  
    </bean>  
    <bean id="order" class="org.jia.Order"<span style="color:ff0000;"> autowire="byName"</span>>  
        <property name="orderNum" value="order000007"></property>  
    </bean>  
</beans>

方式第三種注入:byType

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
<beans>  
    <!--按照byType注入則就與id沒有關係,可以隨便定義id !!!但是不能出現多個此類的id-->  
    <bean id="orderitdfadafaem" class="org.jia.OrderItem">  
        <property name="orderdec" value="item00001"></property>  
    </bean>  
    <bean id="order" class="org.jia.Order" <span style="color:ff0000;">autowire="byType"</span>>  
        <property name="orderNum" value="order000007"></property>  
    </bean>  
</beans> 
autowire="constructor"

需要在Order.java中加入一個構造器

public Order(OrderItem item )  
{   
      orderitem = item;  
}
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
    <bean id="orderItem" class="org.jia.OrderItem"> 
        <property name="orderdec" value="item00001"></property> 
    </bean> 
    <bean id="order" class="org.jia.Order" autowire="constructor"> 
        <property name="orderNum" value="order000007"></property> 
    </bean> 
</beans>

三種注入方式比較

接口注入:

    接口注入模式因爲具備侵入性,它要求組件必須與特定的接口相關聯,因此並不被看好,實際使用有限。

Setter 注入:

    對於習慣了傳統 javabean 開發的程序員,通過 setter 方法設定依賴關係更加直觀。
    如果依賴關係較爲複雜,那麼構造子注入模式的構造函數也會相當龐大,而此時設值注入模式則更爲簡潔。
    如果用到了第三方類庫,可能要求我們的組件提供一個默認的構造函數,此時構造子注入模式也不適用。

構造器注入:

    在構造期間完成一個完整的、合法的對象。
    所有依賴關係在構造函數中集中呈現。
    依賴關係在構造時由容器一次性設定,組件被創建之後一直處於相對“不變”的穩定狀態。
    只有組件的創建者關心其內部依賴關係,對調用者而言,該依賴關係處於“黑盒”之中。

總結

    Spring使用注入方式,爲什麼使用注入方式,這系列問題實際歸結起來就是一句話,Spring的注入和IoC(本人關於IoC的闡述)反轉控制是一回事。
    理論上:第三種注入方式(構造函數注入)在符合java使用原則上更加合理,第二種注入方式(setter注入)作爲補充。
    實際上:我個人認爲第二種注入方式(setter注入)可以取得更加直觀的效果,在使用工作上有不可比擬的優勢,所以setter注入依賴關係應用更加廣泛。

使用p命名空間實現屬性注入(通過setter()方法注入)

作用:使用p命名空間可以簡化配置方法
特點:使用屬性而不是子元素的的形式配置Bean的屬性,從而簡化了Bean的配置。

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!--使用p命名空間注入屬性值-->
    <bean id="zhanShenArmet" class="cn.homework06.model.Equip"
        p:name="戰神頭盔" p:type="頭盔" p:speedPlus="2" p:attackPlus="4"
        p:defencePlus="6" />
    <bean id="lianHuanLoricae" class="cn.homework06.model.Equip"
        p:name="連環鎖子甲" p:type="盔甲" p:speedPlus="6" p:attackPlus="4"
        p:defencePlus="15" />
    <bean id="bosiBoot" class="cn.homework06.model.Equip"
        p:name="波斯追風靴" p:type="靴子" p:speedPlus="8" p:attackPlus="2"
        p:defencePlus="3" />
    <bean id="lanMoRing" class="cn.homework06.model.Equip"
        p:name="藍魔指環" p:type="指環" p:speedPlus="8" p:attackPlus="12"
        p:defencePlus="2" />
    <bean id="zhangsan" class="cn.homework06.model.Player"
        p:armet-ref="zhanShenArmet" p:loricae-ref="lianHuanLoricae"
        p:boot-ref="bosiBoot" p:ring-ref="lanMoRing" />
</beans>

注意:這裏記得導入p命名空間的聲明.

使用方式

  • 對於直接量(基本數據類型、字符串)
    p:屬性名=”屬性值”
  • 對於引用Bean的屬性
    p:屬性名-ref=”Bean的id”

注入不同的數據類型(對於設置注入和構造注入都適用)

1.注入直接量(基本數據類型、字符串)

    <!-- 使用<value>子元素注入字符串、基本數據類型及其包裝類 -->
    <bean id="user" class="entity.User">
    <property name="userame">
        <value>張三</value>
    </property>
        <property name="age">
        <value>23</value>
    </property>
    </bean>

這裏寫圖片描述

        <!-- 使用<![CDATA[]]>標記處理XML特 殊字符 -->
        <property name="specialCharacter1">
            <value><![CDATA[P&G]]></value>
        </property>
        <!-- 把XML特殊字符替換爲實體引用 -->
        <property name="specialCharacter2">
            <value>P&amp;G</value>
        </property>

2.引用其他的Bean組件

<!--使用ref屬性-->
    <bean>
        <property name="dao">
            <ref bean="userDao"/>
        </property>
    </bean>
<!--使用local屬性-->
    <bean>
        <property name="dao">
            <ref local="userDao"/>
        </property>
    </bean>

雖然以上這兩個屬性都是用來指定Bean的id。但區別在於,使用local屬性只能在同一個配置文件中檢索Bean的id,而使用bean屬性可以在其他配置文件中檢索id
3.使用內部Bean

<!-- 定義內部Bean -->
        <property name="innerBean">
            <bean class="entity.User">
                <property name="username">
                    <value>Mr. Inner</value>
                </property>
            </bean>
        </property>

4.注入集合類型的屬性

        <!-- 注入List類型 -->
        <property name="list">
            <list>
                <!-- 定義List中的元素 -->
                <value>足球</value>
                <value>籃球</value>
            </list>
        </property>
        <!-- 注入數組類型 -->
        <property name="array">
            <list>
                <!-- 定義數組中的元素 -->
                <value>足球</value>
                <value>籃球</value>
            </list>
        </property>
        <!-- 注入Set類型 -->
        <property name="set">
            <set>
                <!-- 定義Set或數組中的元素 -->
                <value>足球</value>
                <value>籃球</value>
            </set>
        </property>
        <!-- 注入Map類型 -->
        <property name="map">
            <map>
                <!-- 定義Map中的鍵值對 -->
                <entry>
                    <key>
                        <value>football</value>
                    </key>
                    <value>足球</value>
                </entry>
                <entry>
                    <key>
                        <value>basketball</value>
                    </key>
                    <value>籃球</value>
                </entry>
            </map>
        </property>
        <!-- 注入Properties類型 -->
        <property name="props">
            <props>
                <!-- 定義Properties中的鍵值對 -->
                <prop key="football">足球</prop>
                <prop key="basketball">籃球</prop>
            </props>
        </property>

5.注入null和空字符串

        <!-- 注入空字符串值 -->
        <property name="emptyValue">
            <value></value>
        </property>
        <!-- 注入null值 -->
        <property name="nullValue">
            <null/>
        </property>

AOP 增強類型

  1. 前置增強:在原對象的某方法之前插入的增強處理爲前置增強,
  2. 後置增強:在原對象的某方法正常執行完以後插入的增強處理爲後置增強
  3. 異常拋出增強:特點是在目標方法拋出異常時織入增強處理,使用異常拋出增強,可以爲各功能提供統一的、可拔插的異常處理方案。
  4. 最終增強:特點是無論方法拋出異常還是正常退出,該增強都會得到執行,類似於異常處理機制中的finally塊的作用,一般用於釋放資源。使用最終增強,可以爲各功能提供統一的、可拔插的異常處理方案。
  5. 環繞增強:在目標方法的前後都可以織入增強處理。環繞增強是功能最強大的的增強處理,Spring把目標方法的控制權全部交給了它。在環繞增強處理中,可以獲取或者修改目標方法的參數、返回值,可以對它進行異常處理,甚至可以決定目標方法是否被執行。

使用註解實現loC的配置

1.使用註解定義Bean

package dao.impl;

import org.springframework.stereotype.Component;

import dao.UserDao;
import entity.User;
@Component("userDao")
//此處的@Component("userDao")的作用於在XML配置文件中編寫   <bean id="userDao" class="dao.impl.UserDaoImpl " />等效
public class UserDaoImpl implements UserDao {

    @Override
    public void save(User user) {
        System.out.println("保存用戶信息到數據庫");
        //模擬發生異常
        throw new RuntimeException("發生錯誤異常");
    }

}
  • @Component:用於標註組件。
  • @Repository:用來標註DAO類。
  • @Service:用來標註業務類。
  • @Controller:用來標註控制器類。

2.使用註解實現Bean組件裝配

package service.impl;


import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import dao.UserDao;

import entity.User;
import service.UserService;
@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    //@Autowired(required=false)  required默認爲true,即必須找到匹配的
    //Bean完成裝配,否則拋出異常。
    @Qualifier("userDao")
    private UserDao dao;
    //還可以使用setter()方法和構造方法注入
    //  public void setDao(@Qualifier("userDao") UserDao dao) {
    //      this.dao = dao;
    //  }
    //  
    //  public UserServiceImpl(){
    //      
    //  }
    //  public UserServiceImpl(@Qualifier("userDao") UserDao dao){
    //      
    //  }
    @Override
    public void addNewUser(User user) {
        dao.save(user);
    }

}

@Autowired採用類型匹配的方式爲屬性自動裝配合適的依賴對象,即容器會查找和屬性類型相匹配的Bean組件,並自動爲屬性注入。
若容器中有一個以上類型相匹配的Bean時,則可以使用@Qulifier指定所需的Bean的名稱。

3.加載註解定義的Bean

<?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">
    <!-- 掃描包中註解標註的類 -->
    <context:component-scan base-package="service,dao" />
</beans>

使用Java標準註解完成裝配

除了提供 @Autowired註解,Spring還支持使用JSR-250中定義的@Resource註解實現組件裝配。(JSR的全稱是 Java Specification Requests 是用來規範功能和接口的標準)

package service.impl;


import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import dao.UserDao;

import entity.User;
import service.UserService;
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource(name="userDao")
    //如果沒有顯示地指定Bean的名稱,@Resource註解將根據字段名或者setter方法名產生默認的名稱:如果註解與字段,將使用字段名作爲Bean的名稱
    //如果沒有顯示地指定Bean的名稱,且無法找到與默認Bean名稱匹配的Bean組件,@Resource註解會由按名稱查找的方式自動變爲按類型匹配的方式進行裝配。
    private UserDao dao;


    @Override
    public void addNewUser(User user) {
        dao.save(user);
    }

}

使用註解定義切面

1.AspecJ是一個面向切面的框架,它擴展了Java語言,定義了AOP語法,能夠在編譯期提供代碼的織入,所以他有一個專門的編譯器用來生成遵守字節編碼規範的Class文件。
2.在使用@AspecJ之前要保證,使用的JDK是5.0或其以上版本,否則無法使用註解技術。


/**
 * 使用註解定義切面
 */
@Aspect
public class UserServiceLogger {
    private static final Logger log = Logger.getLogger(UserServiceLogger.class);

    @Pointcut("execution(* service.UserService.*(..))")
    public void pointcut(){}

    @Before("pointcut()")
    public void before(JoinPoint jp) {
        log.info("調用" + jp.getTarget() + jp.getSignature().getName()
                + "方法。方法入參:" + Arrays.toString(jp.getArgs()));
    }

    @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
    public void afterReturning(JoinPoint jp, Object returnValue) {
        log.info("調用" + jp.getTarget() + jp.getSignature().getName()
                + "方法。方法返回值:" + returnValue);
    }
<?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"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 掃描包中註解標註的類 -->
    <context:component-scan base-package="service,dao" />
    <bean class="aop.UserServiceLogger "></bean>
    <aop:aspectj-autoproxy />
</beans>

使用註解定義其他類型的增強

package aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
/**
 *使用註解實現最終增強 
 */
@Aspect
public class AfterLogger {
    private static final Logger log=Logger.getLogger(ErrorLogger.class);

    @After("execution(* service.UserService.*(..))")
    public void afterLogger(JoinPoint jp){
        log.info(jp.getSignature().getName()+"方法執行結束。");
    }
}
package aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
/**
 * 註解實現異常拋出增強
 */
@Aspect
public class ErrorLogger {
    private static final Logger log=Logger.getLogger(ErrorLogger.class);

    @AfterThrowing(pointcut="execution(* service.UserService.*(..))",throwing="e")
    public void afterThrowing(JoinPoint jp,RuntimeException e){
        log.error(jp.getSignature().getName()+"方法發生異常:"+e);
    }
}
package aop;

import java.util.Arrays;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
/**
 *通過註解實現環繞增強
 */
@Aspect
public class AroundLogger {
    private static final Logger log = Logger.getLogger(ErrorLogger.class);
    @Around("execution(* service.UserService.*(..))")
    public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {
        log.info("調用" + jp.getTarget() + "的" + jp.getSignature().getName()
                + "方法。方法入參:" + Arrays.toString(jp.getArgs()));
        try {
            Object result=jp.proceed();
            log.info("調用" + jp.getTarget() + "的" + jp.getSignature().getName()
                    + "方法。方法返回值:" + result);
            return result;
        } catch (Throwable e) {
            // TODO: handle exception
            log.error(jp.getSignature().getName()+"方法發生異常:"+e);
            throw e;
        }finally{
            log.info(jp.getSignature().getName()+"方法結束執行.");
        }
    }
}

簡述Spring實現AOP的幾種方式及各自的使用場合?

  • 通過接口實現、通過註解實現、通過schema形式將POJO方法定義爲增強。
  • 通過接口實現增強處理是較低版本Spring AOP的做法,如果在一個使用低版本Spring AOP開發的項目上進行升級,可以考慮使用複用已經存在的增強類;如果項目採用JDK 5.0以上版本,可以考慮使用@AspectJ註解方式,減少配置的工作量;如果不願意使用註解或項目採用的JDK版本較低無法使用註解,則可以選擇使用配合普通JavaBean的形式。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章