1. 程式人生 > >spring AOP

spring AOP

切入點 動作 3.1 插入 3.2 implement bject version com

本節要點:

  • 掌握AOP概念
  • 掌握AOP的有關術語
  • 掌握spring AOP框架的實現方式

在文章“spring靜態代理和動態代理”中演示了如何使用jdk動態代理功能實現一個最簡單的AOP。使用代理對象將日誌記錄與業務邏輯無關的動作或任務提取出來,設計為一個服務類,這樣的類可以稱之為aspect(切面).

1 AOP定義

  • u AOP把軟件系統分成兩部分:核心關註點和橫切關註點。所謂核心關註點,是業務處理的主要流程,也就是說這個解決方案要做的事。所謂橫切關註點,是與核心關註點無關的部分,常常發生在核心關註點的多處,而各處基本相似,如日誌 、權限等。
  • u 將Cross-cutting concern設計為通用,不介入特定業務對象的一個職責清楚的Aspect對象,這就是Aspect-oriented programming,縮寫即AOP.

AOP並不會取代OOP,而是作為OOP的補充。

  • u AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。

2 AOP有關術語

  • u Advice (通知).

Aspect的具體實現稱之為Advice(處理).上例中DynaProxyHandler類中invoke方法就是Advice的一個具體實現.

  • u Joinpoint(連接點)

Advice在應用程序中被執行的時機稱為Joinpoint(連接點),這個時機可能是某個方法被執行之前或之後(或兩者都有).

  • u Pointcut(切入點)

一組連接點的集合,用於指定哪些Aspect在哪些Joinpoint中織入到應用程序之上.

  • u Target(目標對象)

一個Advice被應用的目標對象.(被AOP框架進行增強處理的對象)

  • u Weave(織入)

Advice被應用至目標對象之上的過程稱這為織入(Weave)

  • u AOP代理(AOP Proxy):

由AOP框架創建的目標對象的代理對象。是被插入了advice的Target Object 。

  • u 引入:

將方法者字段添加到被處理的類中。

術語圖解

技術分享

3 spring AOP框架的實現方式

Spring中的AOP代理由Spring的Ioc容器負責生成、管理,其依賴關系也由Ioc容器負責管理。

AOP編程只需要程序員參加3個部分:

  • u 定義普通業務組件
  • u 定義切入點
  • u 定義增強處理 (定義切面)

進行AOP的關鍵就是定義切入點和增強處理。一旦定義了合適的切入點和增強處理,AOP框架將會自動生成AOP代理。

通常采用AspectJ方式來定義切入點和增強處理,在這種方式下,Spring有如下兩種選擇來定義切入點和增強處理:

  • 基於註解(Annotation)方式:[email protected]@Pointcut等Annotation來標註切入點和增強處理。
  • 基於XML配置文件的管理方式:使用spring配置文件來定義切入點和增強處理

3.1 通過xml配置的方式實現

加入jar包: aopalliance-1.0.jar,aspectjweaver.jar

Log.java前置通知

public class Log implements MethodBeforeAdvice{

    /**

     * @param method 被調用的方法對象,如addUser()方法

     * @param args 被調用的方法的參數

     * @param target 被調用的方法的目標對象

     */

    @Override

    public void before(Method method, Object[] args, Object target)

            throws Throwable {

        System.out.println("執行"+target.getClass().getName()+"的   "+method.getName()+"方法");

    }

}

afterLog.java後置通知

public class AfterLog implements AfterReturningAdvice{

    /**

     * 目標方法執行後執行的通知

     * returnValue 返回值

     * method 被調用的方法對象

     * args 被調用方法對象的參數

     * target 被調用方法對象的目標對象

     */

    @Override

    public void afterReturning(Object returnValue, Method method, Object[] args,

            Object target) throws Throwable {

        System.out.println("after "+target.getClass().getName()+" 的 "+method.getName()+" 被執行");

    }

}

UserService

public interface UserService {

    public void getUser();

    public void addUser();

    public void delUser(String ss);

    public void updUser();

}

UserServiceImpl

public class UserServiceImpl implements UserService{

    @Override

    public void getUser() {

        System.out.println("get user");

    }

    @Override

    public void addUser() {

        System.out.println("add user");

    }

    @Override

    public void delUser( String ss) {

        System.out.println("delete user="+ss);

    }

    @Override

    public void updUser() {

        System.out.println("update user");

    }

}

Beans.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: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/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean name="userService" class="com.silvan.service.UserServiceImpl"></bean>

    <!-- 定義切面 -->

    <bean name="log" class="com.silvan.log.Log"></bean>

    <bean name="afterLog" class="com.silvan.log.AfterLog"/>

    <aop:config>

    <!-- aop:pointcut指定哪些對象的哪些方法訂閱切面, expression指定該切入點關聯的切入點表達式  id指定該切入點的標識符-->

    <aop:pointcut expression="execution(* com.silvan.service.*.*(..))" id="pointcut"/>

    <!--aop:advisor指定切面關聯哪個切入點   advice-ref指定切面  pointcut-ref指定切入點 -->

    <aop:advisor advice-ref="log" pointcut-ref="pointcut" />

    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>

    </aop:config>

</beans>

Test

public class Test {

    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

        UserService us = (UserService) ac.getBean("userService");

//      us.delUser("zhaoliyin");

        us.updUser();

    }

}

使用log4j輸出日誌:

加入jar包:log4j-1.2.14.jar

配置文件:log4j.properties

public class Log implements MethodBeforeAdvice{

    private Logger logger = Logger.getLogger(Log.class) ;

    @Override

    public void before(Method method, Object[] args, Object target)

            throws Throwable {

        logger.info("執行"+target.getClass().getName()+"的   "+method.getName()+"方法");

    }

}

3.2 通過註釋的方式實現

修改配置文件

<?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"

    xsi:schemaLocation="

    http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy/>

    <bean name="userService" class="com.silvan.service.UserServiceImpl"></bean>

    <bean name="log" class="com.silvan.log.Log"></bean>

</beans>

修改切面內容

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

@Aspect

public class Log{

    @Pointcut("execution(* com.silvan.service.*.*(..))") 

    private void anyMethod(){}//定義一個切入點 

   

    @Before("anyMethod() && args(name)")

    public void before(String name){

        System.out.println("前置通知 "+name);

    }

    @AfterReturning("anyMethod()") 

    public void doAfter(){ 

        System.out.println("後置通知"); 

    } 

}

spring AOP