Spring 學習二-----AOP的原理與簡單實踐

1、Spring  AOP的原理

AOP全名Aspect-Oriented Programming,中文直譯爲面向切面(方面)編程。何爲切面,就好比說咱們系統中的權限管理,日誌,事務等咱們均可以將其當作一個個切面。html

Spring AOP 採用的是動態代理的設計模式來實現切面編程的。spring

首先,咱們能夠經過 express

23種設計模式----------代理模式(三) 之 動態代理模式編程

來了解下動態代理模式,再次再也不贅述。設計模式

咱們來看看Spring AOP 是怎樣運用動態代理模式的。在Spring AOP 經過安全

調用流程以下:
一、實現InvocationHandler接口
二、經過ProxyFactoryBean用於建立代理類(根據Advisor生成的Bean,也就是TargetBean的代理)
三、調用invoke方法 
而後,AOP中幾個重要的概念是:
 一、關注點(concern)
   一個關注點能夠是一個特定的問題,概念、或者應用程序的興趣點。總而言之,應用程序必須達到一個目標
   安全驗證、日誌記錄、事務管理都是一個關注點
   在oo應用程序中,關注點可能已經被代碼模塊化了還可能散落在整個對象模型中
二、橫切關注點(crosscutting concern)
   如何一個關注點的實現代碼散落在多個類中或方法中
三、方面(aspect)
   一個方面是對一個橫切關注點模塊化,它將那些本來散落在各處的,
   用於實現這個關注點的代碼規整在一處,能夠經過@Aspect標註或在applictionContext.xml中進行配置: 
      <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"> 
四、建議(advice)通知
   advice是point cut執行代碼,是方面執行的具體實現,如
 <aop:aspect ref="advices">
            <!--切點-->
            <aop:pointcut id="pointcut1" expression="execution(* com.jay.springAOP.aop01.Math.*(..))"/>
            <!--鏈接通知方法與切點-->
            <aop:before method="before" pointcut-ref="pointcut1"/>
            <aop:after method="after" pointcut-ref="pointcut1"/>
        </aop:aspect>
五、切入點(pointcut)
   用於指定某個建議用到何處
<aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> 
六、織入(weaving)
   將aspect(方面)運用到目標對象的過程
七、鏈接點(join point)
  程序執行過程當中的一個點 

 通知類型app

try{
//前置通知
//環繞通知
//調用目標對象方法
//環繞通知
//後置通知
}catch(){
//異常通知
}finally{
//終止通知
}模塊化

 

 

注:圖片來源於:http://blog.csdn.net/lirui0822/article/details/8555691 post

關於PointCut中使用的execution的說明:性能

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

modifiers-pattern:方法的操做權限

ret-type-pattern:返回值

declaring-type-pattern:方法所在的包

name-pattern:方法名

parm-pattern:參數名

throws-pattern:異常

記憶法則就是Java定義一個方法時的樣子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就能夠了。

其中,除ret-type-pattern和name-pattern以外,其餘都是可選的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值爲任意類型;方法名任意;參數不做限制的全部方法。

2、Spring AOP的簡單實踐

一、首先定義一個日誌切面,採用前置通知

package com.jay.springAOP.aopDecorator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
* 一個用於記錄日誌的切面
* Created by xiang.wei on 2017/8/14.
*/
@Component
@Aspect
public class LoggerAdvices {

@Before("execution(* com.jay.springAOP.aopDecorator.*.*(..))")
public void addLogger(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName());
Logger logger= LoggerFactory.getLogger(this.getClass());
//記錄日誌
logger.debug("-------起始操做----------");
logger.debug("-------結束操做-----------");
}
}

二、定義一個用於性能統計的切面,其中定義了一個環繞通知

package com.jay.springAOP.aopDecorator;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * 一個用於性能的統計
 * Created by xiang.wei on 2017/8/14.
 */
@Component
@Aspect
public class PerformanceAdvices {

    @Around("execution(* com.jay.springAOP.aopDecorator.*.*(..))")
    public Object execute(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(pjp.getSignature().getName());
        System.out.println("開始時間:"+System.currentTimeMillis());
        Object result = pjp.proceed();
        System.out.println("結束時間:"+System.currentTimeMillis());
        return result;
    }
}

三、相關的業務代碼

package com.jay.springAOP.aopDecorator;

import org.springframework.stereotype.Service;

/**
 * Created by xiang.wei on 2017/8/14.
 */
@Service("paymentCommand")
public class PaymentCommand {


    public void pay() {
        //執行下訂單操做
        int j=0;
        for (int i=0;i<10000;i++ ) {
            j++;
        }
        //執行支付操做
        System.out.println("進行支付");
    }
}
package com.jay.springAOP.aopDecorator;

import org.springframework.stereotype.Service;

/**
 * Created by xiang.wei on 2017/8/14.
 */
@Service("placeOrderCommand")
public class PlaceOrderCommand{

    public void handleOrder() {
        //執行下訂單操做
        int j=0;
        for (int i=0;i<100000;i++ ) {
            j++;
        }
        System.out.println("進行下單操做");
    }
}

四、測試類:

package com.jay.springAOP.aopDecorator;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by xiang.wei on 2017/8/15.
 */
public class Client {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aopDecorator.xml");

        PlaceOrderCommand placeOrderCommand = ctx.getBean("placeOrderCommand", PlaceOrderCommand.class);
        placeOrderCommand.handleOrder();

        PaymentCommand paymentCommand = ctx.getBean("paymentCommand",PaymentCommand.class);
        paymentCommand.pay();
    }
}

測試結果以下:

相關文章
相關標籤/搜索