Spring學習手札(二)面向切面編程AOP

AOP理解java

  Aspect Oriented Program面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。spring

  可是,這種說法有些片面,由於在軟件工程中,AOP的價值體現的並非代碼方面,更多的是爲了項目的模塊化,而不單單是爲了減小重複代碼。express

  AOP是一種編程思想,爲的是讓模塊自己變得更加內聚,讓開發者更多的關注到業務邏輯的開發。編程

  在面向切面編程裏,把功能分爲核心業務功能和周邊業務功能:app

    核心業務,好比登錄,平常增,刪數據模塊化

    周邊功能,統計,日誌,事務管理。在Spring的面向切面編程AOP思想裏,即被定義爲切面測試

在面向切面的思想裏,核心業務功能和切面功能單獨開發,而後把兩個整合在一塊兒,就是AOP。spa

 

AOP實現原理代理

  AOP底層將採用代理機制進行實現日誌

  接口+實現類:spring採用jdk的動態代理Proxy

  實現類:spring採用cglib字節碼加強

   Spring默認使用JDK動態代理,在須要代理類而不是接口的時候,Spring會自動切換爲使用cglib代理,不過如今的項目都是面向接口開發,因此JDK動態代理相對來講用的仍是多一些。

 

Spring AOP引入了幾個概念

  切面(Aspect),它是跨不一樣Java類層面的橫切性邏輯。能夠經過XML文件中配置的普通類,也能夠在類代碼中使用「@Aspect」 註解去聲明,在運行時,Spring會建立相似Advisor來代替它。其內部包括切入和通知。通俗的講,是要告訴Spring何時,什麼地方,作什麼。

  鏈接點(JoinPoint),程序運行過程當中明確的點,通常是方法的調用。

  通知(Advice),AOP在特定的切入點上知性的加強處理,告訴Spring何時,作什麼。通常會講Advice模擬成一個攔截起,而且在JoinPoint上維護多個Advice,進行層攔截。好比Http鑑權的實現。

  切入點(PointCut),就是帶有通知的鏈接點。要切入的對象,能夠是類,或方法。在Spring中,全部的方法均可以認爲是JoinPoint,均可以添加Advice,可是這並非全部都是咱們真正想要的,而PointCut提供了一組規則,來匹配JointPoint,給知足規則的JointPoint添加Advice。其主要用來修飾JointPoint。

 

Advice的五種通知類型

  前置通知(@Before):在目標方法被調用以前調用通知功能

  後置通知(@After):在目標方法完成以後調用通知,此時不會關心方法的輸出

  返回通知(@After-Returning):在目標方法成功執行以後調用通知

  異常通知(@AfterThrowing):在目標方法拋出異常後調用通知

  環繞通知(@Around):通知包裹了被通知的方法,在被通知的方法調用以前和以後執行自定義的行爲

 

作個小demo

1. 在src下新建bean包,新建Operator類

package bean;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Operator {


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

    @Pointcut("execution(* service.UserService.add())")
    public void  IService(){

    }

    @Before("IService()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("  before Advice");
    }

    @After("IService()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("  after Advice");
    }

    @AfterReturning(pointcut = "IService()", returning = "returnVal")
    public void afterReturn(JoinPoint joinPoint, Object returnVal) {
        System.out.println(" after Advice return " + returnVal);
    }

    @AfterThrowing(pointcut = "IService()", throwing = "errors")
    public void afterThrowing(JoinPoint joinPoint, Throwable errors) {
        System.out.println("afterThrowing Advice ..." + errors);
        System.out.println(" afterThrowing..");
    }

    @Around("IService()")
    public void doAround(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println(" around Advice  before");

        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println(" around Advice  before");
    }
}

 

2. src下新建service包,新建UserService類

package service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void add() {
        System.out.println("UserService add.");
    }

    public boolean delete() {
        System.out.println("UserService delete ..");
        return true;
    }

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

3.配置XML文件,在src下新建applicationContext.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean name="userService" class="service.UserService"></bean>
    <bean name="operator" class="bean.Operator"></bean>

    <aop:config>
        <aop:aspect id="operatorAspect" ref="operator">
            <aop:pointcut id="servicePointCut" expression="execution(* service.UserService.add())"></aop:pointcut>
            <aop:before pointcut-ref="servicePointCut" method="doBefore"></aop:before>
            <aop:after pointcut-ref="servicePointCut" method="doAfter"></aop:after>
            <aop:around pointcut-ref="servicePointCut" method="doAround"></aop:around>
            <aop:after-returning pointcut-ref="servicePointCut" method="afterReturn"
                                 returning="returnVal"></aop:after-returning>
            <aop:after-throwing pointcut-ref="servicePointCut" method="afterThrowing"
                                throwing="errors"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
</beans>

4.測試AOP,在src下新建test.java

import bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

public class test {
    @Test
    public void demo() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService", UserService.class);
        userService.add();
    }

}

5.運行結果

相關文章
相關標籤/搜索