篇二:SpringMVC AOP使用搭建

配置点:

  1、定义切面

  2、定义切入点(满足条件的方法,常用包路径)

  3、定义通知(具体方法)

 

一、SpringMVC使用AOP所需jar包

<dependency>
    <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
</dependency>
<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
</dependency>            

 

二、注解实现

  重点注意:

    进行拦截的类,不能通过new创建,需要添加@Component注解,交由容器管理。否则切面拦截不到。

 

  1、配置注解自动扫描、启用aspectj-autoproxy

<?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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 -->
    <context:component-scan base-package="com.common.service.aspect"/>
    <!-- 激活自动代理功能 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
</beans>

  2、切面类:可以在@Before等通知中,直接定义切入点规则,灵活监听

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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切面Bean
 * @author Shenghany
 * @date 2013-5-28
 */
//声明这是一个组件
@Component
//声明这是一个切面Bean
@Aspect
public class ServiceAspect {

    private final static Log log = LogFactory.getLog(ServiceAspect.class);
    
    //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
    @Pointcut("execution(* cn.ysh.studio.spring.aop.service..*(..))")
    public void aspect(){    }
    
    /*
     * 配置前置通知,使用在方法aspect()上注册的切入点
     * 同时接受JoinPoint切入点对象,可以没有该参数
     */
    @Before("aspect()")
    public void before(JoinPoint joinPoint){
        if(log.isInfoEnabled()){
            log.info("before " + joinPoint);
        }
    }
    
    //配置后置通知,使用在方法aspect()上注册的切入点
    @After("aspect()")
    public void after(JoinPoint joinPoint){
        if(log.isInfoEnabled()){
            log.info("after " + joinPoint);
        }
    }
    
    //配置环绕通知,使用在方法aspect()上注册的切入点
    @Around("aspect()")
    public void around(JoinPoint joinPoint){
        long start = System.currentTimeMillis();
        try {
            ((ProceedingJoinPoint) joinPoint).proceed();
            long end = System.currentTimeMillis();
            if(log.isInfoEnabled()){
                log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
            }
        } catch (Throwable e) {
            long end = System.currentTimeMillis();
            if(log.isInfoEnabled()){
                log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());
            }
        }
    }
    
    //配置后置返回通知,使用在方法aspect()上注册的切入点
    @AfterReturning("aspect()")
    public void afterReturn(JoinPoint joinPoint){
        if(log.isInfoEnabled()){
            log.info("afterReturn " + joinPoint);
        }
    }
    
    //配置抛出异常后通知,使用在方法aspect()上注册的切入点
    @AfterThrowing(pointcut="aspect()", throwing="ex")
    public void afterThrow(JoinPoint joinPoint, Exception ex){
        if(log.isInfoEnabled()){
            log.info("afterThrow " + joinPoint + "\t" + ex.getMessage());
        }
    }
    
}

 

 

三、配置文件实现

  可以直接在aop:before中定义pointcut规则,方便灵活配置前、后、环绕等不同通知监听不同的切入点

<?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/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd           http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd           http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context.xsd"
> <!-- 系统服务组件的切面Bean --> <bean id="serviceAspect" class="cn.common.service.aspect.ServiceAspect"/> <!-- AOP配置 --> <aop:config> <!-- 声明一个切面,并注入切面Bean,相当于@Aspect --> <aop:aspect id="simpleAspect" ref="serviceAspect"> <!-- 配置一个切入点,相当于@Pointcut --> <aop:pointcut expression="execution(* com.common.service..*(..))" id="simplePointcut"/> <!-- 配置通知,相当于@Before、@After、@AfterReturn、@Around、@AfterThrowing --> <aop:before pointcut-ref="simplePointcut" method="before"/> <aop:after pointcut-ref="simplePointcut" method="after"/> <aop:after-returning pointcut-ref="simplePointcut" method="afterReturn"/> <aop:after-throwing pointcut-ref="simplePointcut" method="afterThrow" throwing="ex"/> </aop:aspect> </aop:config> </beans>

  在实现的方法入参使用(JoinPoint joinPoint),获取连接点的信息(类、方法、实现类等等)

 

四、切入点监听语法

  1、切入点表达式通配符:
         *:匹配所有字符
         ..:一般用于匹配多个包,多个参数
         +:表示类及其子类

 

  2、execution匹配子表达式

    规则:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?),除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。

    例子:

//第一个*代表任何返回类型,".."表示service包或子包,第二个"*"表示任意实体,第三个"*"表示任意方法,"(..)"表示任意类型入参
@Pointcut("execution(* com.ccommon.service..*.*(..))") 
//第一个*表示任意的修饰符(public/private/protected)及任意的返回值(void/Object);第二个*表示任意的方法,‘..’表示任意数量的参数; execution(* com.cn21.redisCluster.controller.*(..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)的方法; execution(public * com.cn21.redisCluster.controller.*Controller.*(..))

//service包下任何以User开头的类中的全部方法,入参类型不限,返回类型不限
execute(* com.common.service.User*.*(..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)+返回类型是void的方法; execution(public void com.cn21.redisCluster.controller.*Controller.*(..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public)+返回类型是void的类+第一个参数是int的方法; execution(public void com.cn21.redisCluster.controller.*Controller.*(int,..))
//表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public)+返回类型是void的类+第一个参数是int+第二个参数是int的方法; execution(public void com.cn21.redisCluster.controller.*Controller.*(int,int)):
//任何公共方法的执行,入参类型不限,返回类型不限
execute(public * *(..))

//service包下的没有入参的方法,返回类型不限
execute(* com.common.service..*.*())

//非任何UserService及子类的任何方法
execute(* (!com.common.service.UserService+).*.(..))

//service下的只有一个入参的方法,入参类型不限、返回类型不限
execute(* com.common.service..*.*(*))

//任何以find开头的方法
execute(* find*(..))

  

  3、within:用于匹配连接点所在的Java类或者包

 //匹配Person类中的所有方法
@Pointcut("within(com.cjm.model.Person)")
public void before(){}

//匹配com.cjm包及其子包中所有类中的所有方法
@Pointcut("within(com.cjm..*)")
public void before(){}

 

  4、 this:用于向通知方法中传入代理对象的引用。

@Before("before() && this(proxy)")
public void beforeAdvide(JoinPoint point, Object proxy){
  //处理逻辑
}

 

  5、target:用于向通知方法中传入目标对象的引用。

@Before("before() && target(target)
public void beforeAdvide(JoinPoint point, Object proxy){
    //处理逻辑
}

 

  6、args:用于将参数传入到通知方法中。

@Before("before() && args(age,username)")
public void beforeAdvide(JoinPoint point, int age, String username){
    //处理逻辑
}

 

  7、@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。

@Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation标注的类都将匹配,匹配后类中的方法都是切面的切入点
public void before(){}

 

  8、@target :和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。

@Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
public void before(){}

 

  9、@args :传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。

@Before("@args(com.cjm.annotation.AdviceAnnotation)")
public void beforeAdvide(JoinPoint point){
    //处理逻辑
}

 

  10、@annotation :匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。

@Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
public void before(){}

 

  11、bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的

     id为person的受管Bean中的所有方法都将匹配

@Pointcut("bean(person)")
public void before(){}

 

posted @ 2017-01-09 17:29  刘广平  阅读(395)  评论(0)    收藏  举报