1. 程式人生 > >Spring的AOP配置

Spring的AOP配置

SpringAOP配置

1.先寫一個普通類:

package com.spring.aop;

public class Common {
 public void execute(String username,String password){
     System.out.println("------------------
普通類----------------");
   }

}

2.寫一個切面類,用於合法性校驗和日誌新增:

package com.spring.aop;

public class Check {
 public void checkValidity(){
     System.out.println("------------------

驗證合法性----------------");
 }

public void addLog(JoinPoint j){
  System.out.println("------------------
新增日誌----------------");
  Object obj[] = j.getArgs();
   for(Object o :obj){
    System.out.println(o);
   }
   System.out.println("========checkSecurity=="+j.getSignature().getName());//
這個是獲得方法名
 }

}
3.

配置AOP,使用XML方式:(注意紅色標誌的內容

  <bean id="common" class="com.spring.aop.Common"/>
  <bean id="check" class="com.spring.aop.Check"/>
   
 
<aop:config>
    <aop:aspect id="myAop" ref="check">
      <aop:pointcut id="target"
expression="execution(* com.spring.aop.Common.execute(..))"/>

      <aop:before method="checkValidity" pointcut-ref="target"/>
      <aop:after method="addLog" pointcut-ref="target"/>
    </aop:aspect>
  </aop:config>
</beans>
注意:

execution(* com.spring.aop.*.*(..))"/

這樣寫應該就可以了

這是com.aptech.jb.epet.dao.hibimpl 包下所有的類的所有方法。。

第一個*代表所有的返回值型別

第二個*代表所有的類

第三個*代表類所有方法

最後一個..代表所有的引數。

4.最後寫一個測試:

package com.spring.aop;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client {
 public static void main(String[] args) {
     BeanFactory factory=new ClassPathXmlApplicationContext("applicationContext-aop.xml");
     Common c=(Common) factory.getBean("common");
     c.execute("zhengjunhua","zhengjunhua");

   }
}

注意:

需要新增三個包:spring-aop.jar , aspectjrt.jar aspectjweaver.jar,否則會報錯。

輸出結果:

------------------驗證合法性----------------
------------------
普通類----------------
------------------
新增日誌----------------
zhengjunhua
zhengjunhua
========checkSecurity==execute

Spring實現動態代理配置是有兩種配置檔案:

1xml檔案方式;

2annotation方式(使用AspectJ類庫實現的。)

一、AOP配置annotation方式()搭建annotation開發環境

首先:需要在配置檔案中加入@AspectJ標籤

<aop:aspectj-autoproxy/>

自動幫我產生代理

注意:Spring預設並沒有加入aopxsd檔案,因為我們需要手動加入(紅色部分)

<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-2.5.xsd

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

http://www.springframework.org/schema/context/spring-context-2.5.xsd

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

<context:annotation-config/>

<context:component-scanbase-package="com.wjt276"/>

<aop:aspectj-autoproxy/>

</beans>

另外需要引用aspectJjar包:

aspectjweaver.jar

aspectjrt.jar

()aspectJ類庫

AspectJ是一個專門用來實現動態代理(AOP程式設計)的類庫

AspectJ是面向切面程式設計的框架

Spring使用就是這個類庫實現動態代理的

()AOPannotation例項

要求:在執行save()方法之前加入日誌邏輯

1spring的配置檔案同上面的

2model類、dao層類、service層類都與上面天下一致

3切面類(LogInterceptor)

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.stereotype.Component;

@Aspect

@Component

publicclass LogInterceptor {

@Before("execution(public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User))")

publicvoid before(){

System.out.println("method start...");

}

}

結果:這樣在執行public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User)方法之前就會先執行這個邏輯了。

注意:

1@Aspect:意思是這個類為切面類

2@Componet:因為作為切面類需要Spring管理起來,所以在初始化時就需要將這個類初始化加入Spring的管理;

3@Befoe:切入點的邏輯(Advice)

4execution…:切入點語法

()

三個連線點(切入點)

AspectJ的專業術語

1JoinPoint

切入面

連線點(切入點)

程式執行過程

2PointCut

切入點人集合

當需要定義一個切入點時,則需要使用這個

@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")

public void businessService() {}

3Aspect

切面

4Advice

切入點的邏輯

例如上例中的@Before

5Target

被代理物件

6Weave

織入

()織入點語法

1無返回值、com.wjt276.dao.impl.UserDaoImpl.save方法引數為User

execution(public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User))

2任何包、任何類、任何返回值、任何方法的任何引數

execution(public * *(..))

3任何包、任何類、任何返回值、任何set開頭方法的任何引數

execution(* set*(..))

4任何返回值、com.xyz.service.AccountService類中的任何方法、任何引數

execution(* com.xyz.service.AccountService.*(..))

5任何返回值、com.xyz.service包中任何類中的任何方法、任何引數

execution(* com.xyz.service.*.*(..))

6任何返回值、com.xyz.service包中任何層次子包(..)、任何類、任何方法、任何引數

execution(* com.xyz.service..*.*(..))

7void !void(void)

execution(public void com.xyz.service..*.*(..))

execution(public !void com.xyz.service..*.*(..))

注意:上以是AspectJ的織入點語法,Spring AOP也實現了自己的織入點語法,同樣可以使用

within(com.xyz.service.*)

within(com.xyz.service..*)

this(com.xyz.service.AccountService)

target(com.xyz.service.AccountService)

args(java.io.Serializable)

@target(org.springframework.transaction.annotation.Transactional)

@within(org.springframework.transaction.annotation.Transactional)

@annotation(org.springframework.transaction.annotation.Transactional)

@args(com.xyz.security.Classified)

bean(tradeService)

bean(*Service)

()Advice1@Before

執行方法之前

@Aspect

public class BeforeExample {

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")

public void doAccessCheck() { // ... }}

@Aspect

public class BeforeExample {

@Before("execution(* com.xyz.myapp.dao.*.*(..))")

public void doAccessCheck() { // ... }}

2@ AfterReturning

方法正常執行完之後

@Aspect

public class AfterReturningExample {

@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")

public void doAccessCheck() { // ... }}

@Aspect

public class AfterReturningExample {

@AfterReturning(

pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",

returning="retVal")

public void doAccessCheck(Object retVal) { // ... }}

3@ AfterThrowing

方法丟擲異常之後

@Aspect

public class AfterThrowingExample {

@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")

public void doRecoveryActions() { // ... }}

@Aspect

public class AfterThrowingExample {

@AfterThrowing(

pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",

throwing="ex")

public void doRecoveryActions(DataAccessException ex) { // ... }}

4 @After (finally)

方法丟擲異常被catch之後,需要進行的部分(相當於finally功能)

@Aspect

public class AfterFinallyExample {

@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")

public void doReleaseLock() { // ... }}

5@ Around

在方法之前和之後都要加上

但是需要一個引數ProceedingJoinPoint,並者需要Object retVal = pjp.proceed();

和返回return retVal;

@Aspect

public class AroundExample {

@Around("com.xyz.myapp.SystemArchitecture.businessService()")

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {

// start stopwatch

Object retVal = pjp.proceed();

// stop stopwatch

return retVal; }}

()Pointcut

當多個Advice個有相同的織入點。那麼我們可以定義一個織入點集合,在需要使用的地方,呼叫就可以了。

例如:

@Aspect

@Component

publicclass LogInterceptor {

@Pointcut("execution(public * com.wjt276.dao..*.*(..))")

publicvoid myMethod(){};

@Before(value="myMethod()")

publicvoid before(){

System.out.println("method start...");

}

@AfterReturning("myMethod()")

publicvoid afterReturning(){

System.out.println("method after returning...");

}}

注意:那個空方法,只是為了給Pointcut起個名字,以方便別處使用

()annotatin方式的AOP例項

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

@Aspect

@Component

publicclass LogInterceptor {

@Pointcut("execution(public * com.wjt276.dao..*.*(..))")

publicvoid myMethod(){};

@Before(value="myMethod()")

publicvoid before(){

System.out.println("method start...");

}

@AfterReturning("myMethod()")

publicvoid afterReturning(){

System.out.println("method after returning...");

}

@Around(value="myMethod()")

publicvoid around(ProceedingJoinPoint pjp) throws Throwable{

//因為@around需要傳入一個引數ProceedingJoinPoint進行前後加邏輯

System.out.println("method around start...");

//在需要前後邏輯的中間加入下列語句。表示前後邏輯,可能會丟擲異常Throwable

pjp.proceed();

System.out.println("method around end...");

}

}

二、AOP配置xml方式

xml方式是我們以後使用的比較多的,因為當切面類我們沒有原始碼時、當我們使用第三方的切面類時,我就不能使用annotation的方式,而且如果使用annotation方式一但程式編譯後就不可以修改了。如果使用xml方式就不一樣了,我們只需要修改xml檔案就可以了。

xml方式與annotation的作用是一樣。現在就是例項:

<?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-2.5.xsd

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

http://www.springframework.org/schema/context/spring-context-2.5.xsd

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

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

<context:annotation-config/>

<context:component-scanbase-package="com.wjt276"/>

<beanid="logInterceptor"class="com.wjt276.aop.LogInterceptor"></bean>

<aop:config>

<!-- <aop:pointcut >在此處定義的pointcut是全域性的pointcut可以供所有的aspect使用

id:表示這個pointcut的名稱,以方便使用-->

<aop:pointcutid="myMethod"

expression="execution(public * com.wjt276.service..*.*(..))"/>

<!-- <aop:aspect>表示定義一個切面類(這需要Spring初始化加入其管理)

id:切面類的名稱,

ref:引用哪個bean(需要使用<bean>標籤初始化)-->

<aop:aspectid="logAspect"ref="logInterceptor">

<!-- 在此處定義的pointcut是全域性的pointcut只供當前的aspect使用

id:表示這個pointcut的名稱,以方便使用-->

<aop:pointcutid="myMethod2"

expression="execution(public * com.wjt276.service..*.*(..))"/>

<!--

定義advice時的引數

method:切面邏輯的方法名稱(切面類中的方法名)

pointcut-ref:表示引用哪個pointcut(要求已經在上面定義好了)

pointcut:定義一個pointcut -->

<aop:beforemethod="before"pointcut-ref="myMethod"/>

<aop:after-returningmethod="afterReturning"pointcut="execution(public * com.wjt276.service..*.*(..))"/>

</aop:aspect>

</aop:config>

</beans>

三、AOP實現動態代理注意

因為Spring要實現AOP(面向切面程式設計),需要加入切面邏輯的類就會生成動態代理。在動態代理類中加入切面類從而實現面向切面程式設計,但生成動態代理存在以下注意事項:

1被動態代理的類如果實現了某一個介面,那麼Spring就會利用JDK類庫生成動態代理。

2如果被動態代理的類沒有實現某一個介面,那麼Spring就會利用CGLIB類庫直接修改二進位制碼來生成動態代理(因為利用JDK生成動態代理的類必須實現一個介面),需要在專案中引用CGLIB類庫