国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring Boot Aop

Channe / 1171人閱讀

摘要:面向切面的程序設計思想也是面向切面軟件開發的基礎。與切面相關的編程概念還包括元對象協議主題混入和委托。切面聲明類似于中的類聲明,在中會包含著一些以及相應的。

spring-boot-aop 什么是aop

面向切面的程序設計(Aspect-oriented programming,AOP,又譯作面向方面的程序設計、剖面導向程序設計)是計算機科學中的一種程序設計思想,旨在將橫切關注點與業務主體進行進一步分離,以提高程序代碼的模塊化程度。通過在現有代碼基礎上增加額外的通知(Advice)機制,能夠對被聲明為“切點(Pointcut)”的代碼塊進行統一管理與裝飾,如“對所有方法名以‘set*’開頭的方法添加后臺日志”。該思想使得開發人員能夠將與代碼核心業務邏輯關系不那么密切的功能(如日志功能)添加至程序中,同時又不降低業務代碼的可讀性。面向切面的程序設計思想也是面向切面軟件開發的基礎。

面向切面的程序設計將代碼邏輯切分為不同的模塊(即關注點(Concern),一段特定的邏輯功能)。幾乎所有的編程思想都涉及代碼功能的分類,將各個關注點封裝成獨立的抽象模塊(如函數、過程、模塊、類以及方法等),后者又可供進一步實現、封裝和重寫。部分關注點“橫切”程序代碼中的數個模塊,即在多個模塊中都有出現,它們即被稱作“橫切關注點(Cross-cutting concerns, Horizontal concerns)”。

日志功能即是橫切關注點的一個典型案例,因為日志功能往往橫跨系統中的每個業務模塊,即“橫切”所有有日志需求的類及方法體。而對于一個信用卡應用程序來說,存款、取款、帳單管理是它的核心關注點,日志和持久化將成為橫切整個對象結構的橫切關注點。

切面的概念源于對面向對象的程序設計的改進,但并不只限于此,它還可以用來改進傳統的函數。與切面相關的編程概念還包括元對象協議、主題(Subject)、混入(Mixin)和委托(Delegate)。

AOP中的相關概念

看過了上面解釋,想必大家對aop已經有個大致的雛形了,但是又對上面提到的切面之類的術語有一些模糊的地方,接下來就來講解一下AOP中的相關概念,了解了AOP中的概念,才能真正的掌握AOP的精髓。

Aspect(切面): Aspect 聲明類似于 Java 中的類聲明,在 Aspect 中會包含著一些 Pointcut 以及相應的 Advice。

Joint point(連接點):表示在程序中明確定義的點,典型的包括方法調用,對類成員的訪問以及異常處理程序塊的執行等等,它自身還可以嵌套其它 joint point。

Pointcut(切點):表示一組 joint point,這些 joint point 或是通過邏輯關系組合起來,或是通過通配、正則表達式等方式集中起來,它定義了相應的 Advice 將要發生的地方。

Advice(增強):Advice 定義了在 Pointcut 里面定義的程序點具體要做的操作,它通過 before、after 和 around 來區別是在每個 joint point 之前、之后還是代替執行的代碼。

Target(目標對象):織入 Advice 的目標對象.。

Weaving(織入):將 Aspect 和其他對象連接起來, 并創建 Adviced object 的過程

spring aop

Spring AOP使用純Java實現,它不需要專門的編譯過程,也不需要特殊的類裝載器,它在運行期通過代理方式向目標類織入增強代碼。在Spring中可以無縫地將Spring AOP、IoC和AspectJ整合在一起。Spring AOP構建在動態代理基礎之上,因此,Spring對AOP的支持局限于方法攔截。在Java中動態代理有兩種方式:JDK動態代理和CGLib動態代理

jdk proxy

java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 

* * @author leone * @since 2018-11-09 **/ public class JdkProxy { interface IUserService { Integer delete(Integer userId); } static class UserServiceImpl implements IUserService { @Override public Integer delete(Integer userId) { // 業務 System.out.println("delete user"); return userId; } } // 自定義InvocationHandler static class UserServiceProxy implements InvocationHandler { // 目標對象 private Object target; public UserServiceProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------方法調用前---------"); //執行相應的目標方法 Object result = method.invoke(target, args); System.out.println("------方法調用后---------"); return result; } } public static void main(String[] args) { IUserService userService = new UserServiceImpl(); // 創建調用處理類 UserServiceProxy handler = new UserServiceProxy(userService); // 得到代理類實例 IUserService proxy = (IUserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), new Class[]{IUserService.class}, handler); // 調用代理類的方法 Integer userId = proxy.delete(3); System.out.println(userId); } }

cglib proxy

而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 

* * @author leone * @since 2018-11-09 **/ public class CglibProxy { static class UserService implements MethodInterceptor { private Object target; /** * 業務方法 * * @param userId * @return */ public Integer delete(Integer userId) { System.out.println("delete user"); return userId; } /** * 利用Enhancer類生成代理類 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; // 創建加強器,用來創建動態代理類 Enhancer enhancer = new Enhancer(); // 為加強器指定要代理的業務類(即:為下面生成的代理類指定父類) enhancer.setSuperclass(target.getClass()); // 設置回調:對于代理類上所有方法的調用,都會調用CallBack,而Callback則需要實現intercept()方法進行攔 enhancer.setCallback(this); // 創建動態代理類對象并返回 return enhancer.create(); } /** * @param o * @param method * @param objects * @param methodProxy * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("------方法調用前---------"); Object object = methodProxy.invokeSuper(o, objects); System.out.println("------方法調用后---------"); return object; } } public static void main(String[] args) { UserService userService = new UserService(); UserService proxy = (UserService) userService.getInstance(userService); Integer userId = proxy.delete(2); System.out.println(userId); } }

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

spirng boot aop

    org.springframework.boot
    spring-boot-starter-aop
Advice的主要類型

@Before:該注解標注的方法在業務模塊代碼執行之前執行,其不能阻止業務模塊的執行,除非拋出異常;

@AfterReturning:該注解標注的方法在業務模塊代碼執行之后執行;

@AfterThrowing:該注解標注的方法在業務模塊拋出指定異常后執行;

@After:該注解標注的方法在所有的Advice執行完成后執行,無論業務模塊是否拋出異常,類似于finally的作用;

@Around:該注解功能最為強大,其所標注的方法用于編寫包裹業務模塊執行的代碼,其可以傳入一個ProceedingJoinPoint用于調用業務模塊的代碼,無論是調用前邏輯還是調用后邏輯,都可以在該方法中編寫,甚至其可以根據一定的條件而阻斷業務模塊的調用;

@DeclareParents:其是一種Introduction類型的模型,在屬性聲明上使用,主要用于為指定的業務模塊添加新的接口和相應的實現。

切點表達式

1.通配符

[*] 匹配任意字符,但只能匹配一個元素

[..] 匹配任意字符,可以匹配任意多個元素,表示類時,必須和*聯合使用

[+] 必須跟在類名后面,如Horseman+,表示類本身和繼承或擴展指定類的所有類

2.邏輯運算符

表達式可由多個切點函數通過邏輯運算組成

&& 與操作,求交集,也可以寫成and

例如?execution(* chop(..)) && target(Horseman) ?表示Horseman及其子類的chop方法

|| 或操作,任一表達式成立即為true,也可以寫成 or

例如?execution(* chop(..)) || args(String) ?表示名稱為chop的方法或者有一個String型參數的方法

! 非操作,表達式為false則結果為true,也可以寫成 not

例如?execution(* chop(..)) and !args(String)??表示名稱為chop的方法但是不能是只有一個String型參數的方法

execution() 方法匹配模式串

表示滿足某一匹配模式的所有目標類方法連接點。如execution(* save(..))表示所有目標類中的 save()方法。

由于Spring切面粒度最小是達到方法級別,而execution表達式可以用于明確指定方法返回類型,類名,方法名和參數名等與方法相關的部件,并且在Spring中,大部分需要使用AOP的業務場景也只需要達到方法級別即可,因而execution表達式的使用是最為廣泛的。如下是execution表達式的語法

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

execution(<修飾符> <返回類型> <類路徑> <方法名>(<參數列表>) <異常模式> )

modifiers-pattern:方法的可見性,如public,protected;

ret-type-pattern:方法的返回值類型,如int,void等;

declaring-type-pattern:方法所在類的全路徑名,如com.spring.Aspect;

name-pattern:方法名類型,如buisinessService();

param-pattern:方法的參數類型,如java.lang.String;

throws-pattern:方法拋出的異常類型,如java.lang.Exception;

切點函數

@annotation(annotation-type) 方法注解類名

如下示例表示匹配使用com.leone.aop.AopTest注解標注的方法:

@annotation(com.leone.aop.AopTest)

args(param-pattern) 方法入參切點函數

如下示例表示匹配所有只有一個參數,并且參數類型是java.lang.String類型的方法:

args(java.lang.String)

@args(annotation-type) 方法入參類注解切點函數

如下示例表示匹配使用了com.leone.aop.AopTest注解標注的類作為參數的方法:

@args(com.leone.aop.AopTest)

within(declaring-type-pattern) 類名匹配切點函數

within表達式只能指定到類級別,如下示例表示匹配com.leone.aop.UserService中的所有方法:

within(com.leone.aop.UserService)

@within(annotation-type) 類注解匹配切點函數

如下示例表示匹配使用org.springframework.web.bind.annotation.RestController注解標注的類:

@within(org.springframework.web.bind.annotation.RestController)

target(declaring-type-pattern) 類名切點函數

如下示例表示匹配com.leone.aop.UserService中的所有方法:

target(com.leone.aop.UserService)

this

spring-boot-aop 實戰

配置切面類,實現代理

1.在類上使用 @Component 注解把切面類加入到IOC容器中
2.在類上使用 @Aspect 注解使之成為切面類

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * 描述一個切面類
 *
 * @author leone
 * @since 2018-06-21
 **/
@Slf4j
@Aspect
@Component
public class AopConfig {

    /**
     * 1.通配符
     * [*]  匹配任意字符,但只能匹配一個元素
     * 

* [..] 匹配任意字符,可以匹配任意多個元素,表示類時,必須和*聯合使用 *

* [+] 必須跟在類名后面,如Horseman+,表示類本身和繼承或擴展指定類的所有類 *

* 切點表達式分為 修飾符 返回類型 包路徑 方法名 參數 *

* 2.切點表達式 *

* 3.邏輯運算符 * 表達式可由多個切點函數通過邏輯運算組成 * ** && 與操作,求交集,也可以寫成and *

* 例如?execution(* chop(..)) && target(Horseman) ?表示Horseman及其子類的chop方法 *

* ** || 或操作,任一表達式成立即為true,也可以寫成 or *

* 例如?execution(* chop(..)) || args(String) ?表示名稱為chop的方法或者有一個String型參數的方法 *

* ** ! 非操作,表達式為false則結果為true,也可以寫成 not *

* 例如?execution(* chop(..)) and !args(String)??表示名稱為chop的方法但是不能是只有一個String型參數的方法 */ @Pointcut("execution(* com.leone.boot.aop.service.*.*(..))") public void pointCut() { } /** * 環繞通知在 target 開始和結束執行 * * @param point * @return */ @Around(value = "pointCut()") public Object around(ProceedingJoinPoint point) { long start = System.currentTimeMillis(); String methodName = point.getSignature().getName(); log.info("around method name: {} params: {}", methodName, Arrays.asList(point.getArgs())); try { log.info("around end time: {}", (System.currentTimeMillis() - start) + " ms!"); return point.proceed(); } catch (Throwable e) { log.error("message: {}", e.getMessage()); } return null; } /** * 前置通知在 target 前執行 * * @param joinPoint */ // @Before("@annotation(com.leone.boot.aop.anno.AopBefore)") // @Before("within(com.leone.boot.aop.controller.*)") // @Before("@within(org.springframework.web.bind.annotation.RestController)") // @Before("target(com.leone.boot.aop.controller.UserController)") @Before("@target(com.leone.boot.aop.anno.ClassAop) && @annotation(com.leone.boot.aop.anno.AopBefore)") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); List args = Arrays.asList(joinPoint.getArgs()); log.info("before inform method name: {} param: {}", methodName, args); } /** * 后置通知在target后執行 * * @param joinPoint */ @After("@args(org.springframework.stereotype.Component) && execution(* com.leone.boot.aop.controller.*.*(..))") public void afterMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); List args = Arrays.asList(joinPoint.getArgs()); log.info("after inform method name : {} param: {}", methodName, args); } /** * 后置返回在target返回后執行 * * @param joinPoint * @param result */ @AfterReturning(value = "within(com.leone.boot.aop.controller.*)", returning = "result") public void afterReturning(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); log.info("afterReturning inform method name: {} return value: {}", methodName, result); } /** * 后置異常通知在target異常后執行 * * @param joinPoint * @param ex */ @AfterThrowing(value = "args(com.leone.boot.common.entity.User) && execution(* com.leone.boot.aop.controller.*.*(..))", throwing = "ex") public void afterThrowing(JoinPoint joinPoint, Exception ex) { String methodName = joinPoint.getSignature().getName(); log.info("afterThrowing inform method name: {} exceptions: {}" + methodName, ex); } }

測試類

import com.leone.boot.aop.anno.AopBefore;
import com.leone.boot.aop.anno.ClassAop;
import com.leone.boot.aop.interf.UserService;
import com.leone.boot.common.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author leone
 * @since 2018-06-21
 **/
@Slf4j
@ClassAop
@RestController
@RequestMapping("/api")
public class UserController {

    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }


    @AopBefore
    @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
    public User findOne(@PathVariable Long userId) {
        return userService.findOne(userId);
    }

    @AopBefore
    @RequestMapping("/user")
    public User save(User user) {
        return user;
    }
}

github

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74627.html

相關文章

  • SpringBoot基礎篇AOP之基本使用姿勢小結

    摘要:通知和切點共同定義了關于切面的全部內容,它是什么時候,在何時和何處完成功能引入允許我們向現有的類添加新的方法或者屬性組裝方面來創建一個被通知對象。這可以在編譯時完成例如使用編譯器,也可以在運行時完成。和其他純框架一樣,在運行時完成織入。 原文:190301-SpringBoot基礎篇AOP之基本使用姿勢小結 一般來講,談到Spring的特性,繞不過去的就是DI(依賴注入)和AOP(切...

    timger 評論0 收藏0
  • 貓頭鷹的深夜翻譯:使用SpringBoot和AspectJ實現AOP

    摘要:我們會寫切面來攔截對這些業務類和類的調用。切面定義何時攔截一個方法以及做什么和在一起成為切面連接點當代碼開始執行,并且切點的條件滿足時,通知被調用。 前言 這篇文章會幫助你使用Spring Boot Starter AOP實現AOP。我們會使用AspectJ實現四個不同的通知(advice),并且新建一個自定義的注解來追蹤方法的執行時間。 你將會了解 什么是交叉分割關注點(cross...

    meislzhua 評論0 收藏0
  • SpringSpring Boot和TestNG測試指南 - 測試AOP

    摘要:首先先來看我們事先定義的以及。可以看到會修改方法的返回值,使其返回。例子測試的行為最簡單的測試方法就是直接調用,看看它是否使用返回。先看這段代碼這些是利用提供的和來判斷是否被代理了的實現是通過動態代理來做的。 Github地址 Spring提供了一套AOP工具,但是當你把各種Aspect寫完之后,如何確定這些Aspect都正確的應用到目標Bean上了呢?本章將舉例說明如何對Spring...

    changfeng1050 評論0 收藏0
  • Spring Boot中自定義注解+AOP實現主備庫切換

    摘要:示例代碼如下添加的設置默認的配置對應的是原來的如何使用注解從主庫到備庫的切換 摘要: 本篇文章的場景是做調度中心和監控中心時的需求,后端使用TDDL實現分表分庫,需求:實現關鍵業務的查詢監控,當用Mybatis查詢數據時需要從主庫切換到備庫或者直接連到備庫上查詢,從而減小主庫的壓力,在本篇文章中主要記錄在Spring Boot中通過自定義注解結合AOP實現直接連接備庫查詢。 一.通過A...

    zhisheng 評論0 收藏0
  • Spring Boot 2.x(十一):AOP實戰--打印接口日志

    摘要:接口日志有啥用在我們日常的開發過程中,我們可以通過接口日志去查看這個接口的一些詳細信息。在切入點返回內容之后切入內容可以用來對處理返回值做一些加工處理。 接口日志有啥用 在我們日常的開發過程中,我們可以通過接口日志去查看這個接口的一些詳細信息。比如客戶端的IP,客戶端的類型,響應的時間,請求的類型,請求的接口方法等等,我們可以對這些數據進行統計分析,提取出我們想要的信息。 怎么拿到接口...

    Youngdze 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<