Spring IOC DI AOP 的簡單理解及應用


Spring兩大特性:IOC 和AOP。IOC 控制反轉,AOP 面向切面編程

  spring 核心容器的主要組件時Bean工廠(BeanFactory) ,Bean 工廠使用控制反轉模式來降低程序代碼之間的耦合度,並提供了面向切面編程的實現。

  Spring 常用的注解

  1. @Controller :用於標注控制器成組件。
  2. @Service:用於標注業務成組件。
  3. @Component : 用於標注這是一個受spring 容器管理的組件,組件引用名稱是類名, 第一個字母小寫。也可以使用@Component("beanName")指定組件的名稱
  4. @Reposirty:用於標注數據庫訪問組件,即DAO組件。
  5. @Bean:方法級別的注解,主要用於@Configuration 或@Component 注解的類里, @Bean 注解的方法會產生一個Bean對象,該對象由Spring管理並放在IOC容器中。引用名稱是方法名, 也可以使用@Bean(name = "beanName")指定組件名稱
  6. @Scope("prototype"):將組件的范圍設置為原型的(即多例)。保證每一個請求有一個單獨的action來處理,避免action的線程問題。由於Spring默認是單例模式,只會創建一個action對象,每次訪問都是同一個對象,容易產生並發問題,數據不安全。
  7. @Autowired:默認按照類型進行自動裝配,在容器查找匹配的bean, 當僅有一個匹配的Bean時,Spring將其注入@Autowired標注的變量中。
  8. @Resource:默認按名稱進行自動裝配,當找不到與名稱匹配的Bean時會按照類型裝配。

    能夠明確該類時一個控制器類組件時,就用@Controller;

    能夠明確該類是一個服務類組件時,就用@Service;

    能夠明確該類是一個數據訪問組件時,就用@Repository;

    不明確它的作用時,使用@Component;

  控制反轉IOC

  創建對象的控制權反轉到Spring框架上。

  通常,實例化一個對象時,都是使用類的構造方法來new一個對象,這個過程是由我們自己來控制的,而控制反轉就是把new對象的操作交給Spring容器

  IOC的主要實現方式:依賴查找、依賴注入。依賴注入是一種更可取的方式。

  依賴查找,依賴注入的區別?

  依賴查找:主要是容器為組件提供一個回調接口和上下文環境。組件必須自己使用容器提供的API來查找資源和協作對象,控制反轉僅體現在那些回調方法上,容器調用這些回調方法,應用代碼獲取到資源。

  依賴注入:組件不做定位查詢,只提供標磚的JAVA方法讓容器去決定依賴關系,容器全權負責組件的裝配,把符合依賴關系的對象通過JAVA Bean 屬性或構造方法傳遞給需要的對象。

    

  IOC容器:具有依賴注入功能的容器,可以創建對象的容器。IOC容器負責實例化、定位、配置應用程序中的對象並建立這些對象之間的依賴。

  依賴注入:由IOC容器動態地將某個對象所需要的外部資源(包括對象、資源、常量數據)注入到組件之中

  Spring依賴注入的方式主要有四個:基於注解注入、Set注入方式、構造器注入方式、靜態工廠注入方式。推薦使用基於注解注入的方式,配置少,比較方便。

  @Autowired和@Resource的區別

  共同點: @Autowired和@Resource都是用來裝配Bean的, 都可以寫在字段、setter方法上。

  不同點:

  @Autowired默認按照類型進行自動裝配,該注解屬於Spring,.默認情況下要求依賴對象必須存在,如果允許為null,需要設置required屬性為false。如果要使用名稱進行裝配,可以和@QualiFier 注解一起使用

  

@Autowired
@QualiFier("beanName")
private BeanNameService beanNameService;

 

  @Resource默認按照名稱進行裝配,該注解屬於J2EE,名稱可以通過name屬性來指定。如果沒有指定name屬性,當注解寫在字段上時,默認取字段名進行裝配;如果注解寫在setter方法上,默認取屬性名進行裝配。當找不到與名稱匹配的Bean時,會按照類型進行裝配,但是,name屬性一旦指定,就只會按照名稱進行裝配。

@Resource(name="beanNameService")
private BeanNameService beanNameService;

  面向切面編程AOP

 

  AOP一般應用於:簽名驗簽、參數校驗、日志記錄、事務控制、權限控制、性能統計、異常處理等。

  切面(Aspect):共有功能的實現。如日志切面、權限切面、驗簽切面等。在實際開發中通常是一個存放共有功能實現的標准Java類。當Java類使用了@Aspect注解修飾時,就能被AOP容器識別為切面。

  通知(Advice):切面的具體實現。就是要給目標對象織入的事情。以目標方法為參照點,根據放置的地方不同,可分為前置通知、后置通知、異常通知、最終通知、環繞通知。通常切面類中的一個方法,具體屬於哪類通知,通過方法上的注解區分。

  連接點(JoinPoint):程序在運行過程中能夠插入切面的地點。例如,方法調用、異常拋出等。Spring只支持方法級的連接點。一個類的所有方法前、后、拋出異常時等都是連接點。

  切入點(Pointcut):用於定義通知應該切入到哪些連接點上。不同的通知通常需要切入到不同的連接點上,這種精准的匹配是由切入點的正則表達式來定義的。

  目標對象(Target):那些即將切入切面的對象,也就是那些被通知的對象。這些對象專注業務本身的邏輯,所有的共有功能等待AOP容器的切入。

  代理對象(Proxy):將通知應用到目標對象之后被動態創建的對象。可以簡單地理解為,代理對象的功能等於目標對象本身業務邏輯加上共有功能。代理對象對於使用者而言是透明的,是程序運行過程中的產物。目標對象被織入共有功能后產生的對象。

  織入(Weaving):將切面應用到目標對象從而創建一個新的代理對象的過程。這個過程可以發生在編譯時、類加載時、運行時。Spring是在運行時完成織入,運行時織入通過Java語言的反射機制與動態代理機制來動態實現。

  Pointcut用法

   

execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

  修飾符匹配 modifier-pattern? 例:public private

  返回值匹配 ret-type-pattern 可以用 * 表示任意返回值

  類路徑匹配 declaring-type-pattern? 全路徑的類名

  方法名匹配 name-pattern 可以指定方法名或者用 * 表示所有方法;set* 表示所有以set開頭的方法

  參數匹配 (param-pattern) 可以指定具體的參數類型,多個參數用“,”分隔;可以用 * 表示匹配任意類型的參數;可以用 (..) 表示零個或多個任意參數

  異常類型匹配throws-pattern? 例:throws Exception

  其中后面跟着 ? 表示可選項

@Pointcut("execution(public * com.project.springbootdemo.controller.*.*(..))")
private void sign() {
 
}

  示例:

  

/**
SignAop類使用了@Aspect注解,則該類可以被AOP容器識別為切面。

*/

@Aspect
@Component
public class SignAop {
 
/**@Pointcut聲明一個切入點,范圍為controller包下所有的類的所有方法*/
    @Pointcut("execution(public * cn.wbnull.springbootdemo.controller.*.*(..))")
    private void signAop() {
 
    }
     //doBefore()方法使用@Before("signAop()")注解,表示前置通知(在某連接點之前執行的通知),但這個通知不能阻止連接點之前的執行流程,除非它拋出一個異常。
    @Before("signAop()")
    public void doBefore(JoinPoint joinPoint) throws Exception {
        //code
       }
 
//doAfterReturning()方法使用@AfterReturning(value = "signAop()", returning = "params")注解,表示后置通知(在某連接點正常完成后執行的通知),通常在一個匹配的方法返回的時候執行。
    @AfterReturning(value = "signAop()", returning = "params")
    public JSONObject doAfterReturning(JoinPoint joinPoint, JSONObject params) {
        //code
        }
}

//實際運行時,在進入controller包下所有方法前,都會進入doBefore()方法,在controller包下方法執行完成后,都會進入doAfterReturning()方法。

 

 

 

 

 

 

 

 

 

  


免責聲明!

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



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