Spring AOP + AspectJ framework

 转载出处:http://www.blogjava.net/fancydeepin ] 

 

AOP(Aspect Orient Programming),也就是常说的面向方面编程,它是作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)


中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。

简单点来说,它就是一个拦截器可以拦截一些进程,例如,当某个方法执行时,Spring AOP 可以拦截该执行的方法,并允许在方法执行之前或之后添加额外的功能,

以上如若解释的不好,勿喷 -_- ||

AspectJ 是一个基于 Java 语言的 AOP 框架,提供了强大的 AOP 功能,Spring 从 2.0 起,对 AspectJ 功能都提供了支持 .

几个常用的 AspectJ 注解 : 

    @Before   在方法执行前被执行

    @After     在方法执行后被执行

    @AfterReturning     在方法执行后被执行,并同时拦截方法返回的结果

    @AfterThrowing      在方法抛出异常时候被执行,若方法不抛出异常,则不会被执行

    @Around   这个,不知道要怎么解释了,比较不好解释,就像你拦截了一个方法,并在适当的时候给予放行,放行前后可以做额外的处理,下面看示例就很容易明白了

环境 : 

 

 

 
eclipse  3.6
maven  3.0.4
spring   3.0.5
aspectj 1.6.11
 

 


pom.xml 清单 : 

 

 

 

 

 
< project  xmlns ="http://maven.apache.org/POM/4.0.0"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" >
   < modelVersion > 4.0.0 </ modelVersion >
   < groupId > com.fancy </ groupId >
   < artifactId > spring-aop </ artifactId >
   < packaging > war </ packaging >
   < version > 1.0 </ version >
   < name > spring-aop Maven Webapp </ name >
   < url > http://maven.apache.org </ url >
  
  
< properties >
     < spring .version > 3.0.5.RELEASE </ spring.version >
     < aspectj .version > 1.6.11 </ aspectj.version >
   </ properties >
  
  
< dependencies >
    
    
< dependency >
       < groupId > org.springframework </ groupId >
       < artifactId > spring-core </ artifactId >
       < version > ${spring.version} </ version >
     </ dependency >
 
    
< dependency >
       < groupId > org.springframework </ groupId >
       < artifactId > spring-context </ artifactId >
       < version > ${spring.version} </ version >
     </ dependency >
 
    
<!--  Spring AOP + AspectJ  -->
     < dependency >
       < groupId > org.springframework </ groupId >
       < artifactId > spring-aop </ artifactId >
       < version > ${spring.version} </ version >
     </ dependency >
 
    
< dependency >
       < groupId > org.aspectj </ groupId >
       < artifactId > aspectjrt </ artifactId >
       < version > ${aspectj.version} </ version >
     </ dependency >
 
    
< dependency >
       < groupId > org.aspectj </ groupId >
       < artifactId > aspectjweaver </ artifactId >
       < version > ${aspectj.version} </ version >
     </ dependency >
    
    
< dependency >
       < groupId > junit </ groupId >
       < artifactId > junit </ artifactId >
       < version > 4.7 </ version >
       < scope > test </ scope >
     </ dependency >
    
  
</ dependencies >
  
  
< build >
     < finalName > spring-aop </ finalName >
   </ build >
  
</ project >
 

 


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:p ="http://www.springframework.org/schema/p"  xmlns:tx ="http://www.springframework.org/schema/tx"
  xmlns:aop ="http://www.springframework.org/schema/aop"  xmlns:context ="http://www.springframework.org/schema/context"
  xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
    
  
<!--  开启注解  -->
   < context:annotation-config />
   <!--  自动扫描  -->
   < context:component-scan  base-package ="com.fancy" />
   <!--  启动 AspectJ 支持  -->
   < aop:aspectj-autoproxy  />
    
</ beans >
 

 


还是来编写 HelloWorld : 

1 . 编写 HelloWorld 接口

 

 

 

 

 
package  com.fancy.service;

public   interface  HelloWorld {

    
public   void  sayHi();
    
    
public   void  sayHiAround(String username);
    
    
public   void  sayHiThrowException()  throws  Exception;
    
    
public  String  sayHiReturnValue();
    
}
 

 


2 . 编写 HelloWorld 接口的实现,并将其注解成 spring 的一个组件

 

 

 

 

 
package  com.fancy.service.impl;

import  com.fancy.service.HelloWorld;
import  org.springframework.stereotype.Component;

@Component

public   class  HelloWorldImpl  implements  HelloWorld {

    
public   void  sayHi() {
        
        System.out.println(
" sayHi ---->> Hi fancy ! " );
    }

    
public   void  sayHiAround(String username) {
        
        System.out.println(
" sayHiAround ---->> Hi  "   +  username  +   "  ! " );
    }

    
public   void  sayHiThrowException()  throws  Exception {
        
        System.out.println(
" sayHiThrowException ---->> Hi fancy ! " );
        
throw   new  Exception( " Throw an exception here !!!! " );
    }

    
public  String sayHiReturnValue() {
        
        System.out.println(
" sayHiReturnValue ---->> Hi fancy ! " );
        
return   " fancy " ;
    }
    
}
 

 


3 . 编写方面代码 : 

AspectJ @Before 示例

 

 

 

 

 
package  com.fancy.aspect;

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

@Aspect
@Component

public   class  MyAspect {

    @Before(
" execution (* com.fancy.service.HelloWorld.sayHi(..)) " )
    
public   void  logBefore(JoinPoint   joinPoint){
        
        System.out.println(
" logBefore() Method Invoke! " );
        System.out.println(
" Hijack Method Name :  "   +  joinPoint.getSignature().getName());
    }
    
}
 


其中,@Before("execution (* com.fancy.service.HelloWorld.sayHi(..))") 中的 execution (* com.fancy.service.HelloWorld.sayHi(..)) 是切入点表达式,

更多的帮助信息可以查看 spring 的帮助文档,spring 3.0.5 的帮助文档中是在 第 7  章的 7.2.3.4 小节,因为文档上说的也不是太清楚,在这里我也不好说话,

其中的 execution 是用于匹配方法执行的连接点,那个 * 号所占的位不知道是不是代表方法的访问权限,文档上没说,网上也没找到相关解释,哪位知道的望告知啊~~

接下来的 com.fancy.service.HelloWorld.sayHi 就很明显了,就是切入点方法名,再接下来的是 (..),(..) 代表匹配任意数量的参数,可以是 0 个也可以是多个 ;

如果你确定这个方法不需要参数,可以直接使用 (),还可以使用 (*) 来匹配一个任意类型的参数,还可以使用 (* , String),这样代表匹配两个参数,第二个参数必须是

String 类型的参数,这些在 spring 帮助文档的 7.2.3.4 小节都有说到,在这里就不多说了,可以自己去看,英文的看起来更带劲 *_*

再接下来的是 JoinPoint 接口,org.aspectj.lang.JoinPoint 接口表示的是目标类连接点对象,这个我也找不到相关的 API,只能手工整理一下了 : 

JoinPoint     API 

     java.lang.Object                getThis() :获取代理对象本身;

     java.lang.Object           getTarget() :获取连接点所在的目标对象; 

    Signature                   getSignature() :获取连接点的方法签名对象; 

    java.lang.Object[]             getArgs():获取连接点方法运行时的入参列表; 
             

Junit 测试

 

 

 

 

 
package  junit.test;

import  org.junit.Test;
import  org.junit.BeforeClass;
import  com.fancy.service.HelloWorld;
import  org.springframework.context.ApplicationContext;
import  org.springframework.context.support.ClassPathXmlApplicationContext;

public   class  TestApp {
    
    
private   static  ApplicationContext context  =   null ;
    
    @BeforeClass
    
public   static   void  setUpBeforeClass()  throws  Exception {

        context 
=   new  ClassPathXmlApplicationContext( " applicationContext.xml " );
    }
    
    @Test
    
public   void  testMethod()  throws  Exception{
        
        HelloWorld helloworld 
=  (HelloWorld)context.getBean( " helloWorldImpl " );
        helloworld.sayHi();
    }

}
 


后台输出 : 

 

 

 

 

 
logBefore() Method Invoke
!
Hijack Method Name : sayHi
sayHi 
---->>  Hi fancy  !
 

 


AspectJ @After 示例

 

 

 

 

 
package  com.fancy.aspect;

import  org.aspectj.lang.JoinPoint;
import  org.aspectj.lang.annotation.After;
import  org.aspectj.lang.annotation.Aspect;
import  org.springframework.stereotype.Component;

@Aspect
@Component

public   class  MyAspect {


    @After(
" execution (* com.fancy.service.HelloWorld.sayHi(..)) " )
    
public   void  logAfter(JoinPoint   joinPoint){
        
        System.out.println(
" logAfter() Method Invoke! " );
        System.out.println(
" Hijack Method Name :  "   +  joinPoint.getSignature().getName());
    }
    
}
 


Junit 测试

 

 

 

 

 
@Test
    
public   void  testMethod()  throws  Exception{
        
        HelloWorld helloworld 
=  (HelloWorld)context.getBean( " helloWorldImpl " );
        helloworld.sayHi();
    }
 


后台输出 : 

 

 

 

 

 
sayHi 
---->>  Hi fancy  !
logAfter() Method Invoke !
Hijack Method Name : sayHi
 

 


AspectJ @AfterReturning 示例

 

 

 

 

 
package  com.fancy.aspect;

import  org.aspectj.lang.JoinPoint;
import  org.aspectj.lang.annotation.AfterReturning;
import  org.aspectj.lang.annotation.Aspect;
import  org.springframework.stereotype.Component;

@Aspect
@Component

public   class  MyAspect {


    @AfterReturning(pointcut 
=   " execution (* com.fancy.service.HelloWorld.sayHiReturnValue(..)) " , returning  =   " returnValue " )
    
public   void  logAfterReturning(JoinPoint   joinPoint, Object /* String */  returnValue){
        
        System.out.println(
" logAfterReturning() Method Invoke! " );
        System.out.println(
" Hijack Method Name :  "   +  joinPoint.getSignature().getName());
        System.out.println(
" The Return Value Is :  "   +  returnValue);
    }
    
}
 


Junit 测试

 

 

 

 

 
@Test
    
public   void  testMethod()  throws  Exception{
        
        HelloWorld helloworld 
=  (HelloWorld)context.getBean( " helloWorldImpl " );
        helloworld.sayHiReturnValue();
    }
 


后台输出 : 

 

 

 

 

 
sayHiReturnValue 
---->>  Hi fancy  !
logAfterReturning() Method Invoke !
Hijack Method Name : sayHiReturnValue
The Return Value Is : fancy
 

 


AspectJ @AfterThrowing 示例

 

 

 

 

 
package  com.fancy.aspect;

import  org.aspectj.lang.JoinPoint;
import  org.aspectj.lang.annotation.AfterThrowing;
import  org.aspectj.lang.annotation.Aspect;
import  org.springframework.stereotype.Component;

@Aspect
@Component

public   class  MyAspect {


    @AfterThrowing(pointcut 
=   " execution (* com.fancy.service.HelloWorld.sayHiThrowException(..)) " , throwing  =   " error " )
    
public   void  logAfterThrowing(JoinPoint joinPoint, Throwable error){
        
        System.out.println(
" logAfterThrowing() Method Invoke! " );
        System.out.println(
" Hijack Method Name :  "   +  joinPoint.getSignature().getName());
        System.out.println(
" Exception Message  : "   +  error);
    }
    
}
 


Junit 测试

 

 

 

 

 
@Test
    
public   void  testMethod()  throws  Exception{
        
        HelloWorld helloworld 
=  (HelloWorld)context.getBean( " helloWorldImpl " );
        helloworld.sayHiThrowException();
    }
 


后台输出 : 

 

 

 

 

 
sayHiThrowException 
---->>  Hi fancy  !
logAfterThrowing() Method Invoke !
Hijack Method Name : sayHiThrowException
Exception Message  :java.lang.Exception: Throw an exception here 
!!!!
 


若将 HelloWorldImpl 类中 sayHiThrowException 方法的异常抛出注释掉,

 

 

 

 

 
public   void  sayHiThrowException()  throws  Exception {
        
        System.out.println(
" sayHiThrowException ---->> Hi fancy ! " );
        
// throw new Exception("Throw an exception here !!!!");
    }
 


其余不变,再次执行 Junit 测试,后台输出 : 

 

 

 

 

 
sayHiThrowException 
---->>  Hi fancy  !
 


这就说明,当该方法能够运行正常的时候,没有抛出异常,则,logAfterThrowing 不会被执行 .


AspectJ @Around 示例

 

 

 

 

 
package  com.fancy.aspect;

import  java.util.Arrays;

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

@Aspect
@Component

public   class  MyAspect {


    @Around(
" execution (* com.fancy.service.HelloWorld.sayHiAround(..)) " )
    
public   void  logAround(ProceedingJoinPoint   joinPoint)  throws  Throwable {
        
        System.out.println(
" logAround() Method Invoke! " );
        System.out.println(
" Hijack Method Name  :  "   +  joinPoint.getSignature().getName());
        System.out.println(
" Hijack Arguments Is :  "   +  Arrays.toString(joinPoint.getArgs()));
        System.out.println(
" Around before : can do something here ! " );
        joinPoint.proceed(); 
// 放行
        System.out.println( " Around after  : can do something here ! " );
    }
    
}
 


Junit 测试

 

 

 

 

 
@Test
    
public   void  testMethod()  throws  Exception{
        
        HelloWorld helloworld 
=  (HelloWorld)context.getBean( " helloWorldImpl " );
        helloworld.sayHiAround(
" fancy " );
    }
 


后台输出 : 

 

 

 

 

 
logAround() Method Invoke
!
Hijack Method Name  : sayHiAround
Hijack Arguments Is : [fancy]
Around before : can 
do  something here  !
sayHiAround  ---->>  Hi fancy  !
Around after  : can  do  something here  !
 


其中,需要提一下 ProceedingJoinPoint 接口 :

ProceedingJoinPoint 继承于 JoinPoint,是其子接口,它新增了两个用于执行连接点方法的方法: 

     java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法; 

     java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。


最后附上 spring 3.0.5 帮助文档中的一些信息 : 

 

 

 

 

Some examples of common pointcut expressions are given below.

  • the execution of any public method:

    execution(public * *(..))public * *(..))
  • the execution of any method with a name beginning with "set":

    execution(* set*(..))
  • the execution of any method defined by the AccountService interface:

    execution(* com.xyz.service.AccountService.*(..))
  • the execution of any method defined in the service package:

    execution(* com.xyz.service.*.*(..))
  • the execution of any method defined in the service package or a sub-package:

    execution(* com.xyz.service..*.*(..))
  • any join point (method execution only in Spring AOP) within the service package:

    within(com.xyz.service.*)
  • any join point (method execution only in Spring AOP) within the service package or a sub-package:

    within(com.xyz.service..*)
  • any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:

    this(com.xyz.service.AccountService)(com.xyz.service.AccountService)

     

    'this' is more commonly used in a binding form :- see the following section on advice for how to make the proxy object available in the advice body.

     

  • any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:

    target(com.xyz.service.AccountService)

     

    'target' is more commonly used in a binding form :- see the following section on advice for how to make the target object available in the advice body.

     

  • any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable:

    args(java.io.Serializable)

    'args' is more commonly used in a binding form :- see the following section on advice for how to make the method arguments available in the advice body.

    Note that the pointcut given in this example is different to execution(* *(java.io.Serializable)): the args version matches if the argument passed at runtime is Serializable, the execution version matches if the method signature declares a single parameter of type Serializable.

  • any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation:

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

     

    '@target' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

     

  • any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:

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

     

    '@within' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

     

  • any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:

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

     

    '@annotation' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

     

  • any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the@Classified annotation:

    @args(com.xyz.security.Classified)

     

    '@args' can also be used in a binding form :- see the following section on advice for how to make the annotation object(s) available in the advice body.

     

  • any join point (method execution only in Spring AOP) on a Spring bean named 'tradeService':

    bean(tradeService)
  • any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service':

    bean(*Service)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值