SpringAop的使用

来源:互联网 发布:2017年网络灰色收入 编辑:程序博客网 时间:2024/05/16 10:29

SpringAop的使用,使用xml和@注解配置两种方式

需要jar包:
 
 
AOP执行顺序:
前置通知,是在方法前执行吗?
环绕通知执行,进入方法...
执行save()方法...
@后置通知,是在方法后执行吗?
最终通知 执行...
@异常通知,程序出现异常了吗?(出现异常通知则后置通知不执行)
环绕通知,退出方法...

========================================================

第一步:使用注解方式建立切面类,代码如下:

package com.newer.test;

import java.lang.reflect.Method;
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.aspectj.lang.reflect.MethodSignature;

/**
 * 测试Spring AOP机制 <br/>
 * 使用注解方式 配置切面 [@Aspect]
 * @author RSun
 * 2012-2-21上午12:07:17
 */
@Aspect
public class TestAOP {
/** 
 * 声明一个切入点  <br/>
 */
@SuppressWarnings("unused")
@Pointcut("execution(* com.newer.service.impl.PersonServiceImpl.*(..))")
private void anyMethod(){}
/**
 * 注解定义前置通知(方法执行前执行) <br/>
 * 需指明切入点 <br/>
 */
@Before("anyMethod()")

public void doAccessCheck() {

        System.out.println("前置通知,是在方法前执行吗?");

}
/**
 * 前置通知,获取被拦截方法的参数 <br/>
 * 根据参数拦截相关方法,被拦截的方法参数类型需相同 <br/>
 * args(name) 里参数name必须和*Two(String name)参数名相同[name-name]<br/>
 * 需指明切入点 ,可以指定多个。 用 [||、&&]<br/>
 */
@Before("anyMethod() && args(name)")
public void doAccessCheckTwo(String name) {
        System.out.println("获取传入参数的前置通知,传入参数name:" + name);

}

/**
 * 后置通知(方法执行成功后执行) <br/>
 * 需指明切入点 <br/>
 */
@AfterReturning("anyMethod()")
public void doAccessReturning() {
        System.out.println("后置通知,是在方法后执行吗?");
}
/**
 * 后置通知,获取被拦截方法的返回数据 <br/>
 * 注意参数的设定 <br/>
 * 需指明切入点 <br/>
 */
@AfterReturning(pointcut="anyMethod()", returning="result")
public void doAccessReturningTwo(String result) {
        System.out.println("带返回值的后置通知,返回值result:"+result);
}
/**
 * 最终通知 (finally块)<br/>
 * 需指明切入点 <br/>
 */
@After("anyMethod()")
public void doAfter() {
        System.out.println("最终通知 执行...");
}
/**
 * 例外通知(异常通知catch块) <br/>
 * 后置通知不执行(最终通知在异常通知前执行) <br/>
 * 需指明切入点 <br/>
 */
@AfterThrowing("anyMethod()")
public void doAfterThrowing() {
        System.out.println("异常通知,程序出现异常了吗?");
}
/**
 * 例外通知,获取异常 <br/>
 * 需指明切入点 <br/>
 */
@AfterThrowing(pointcut="anyMethod()", throwing="e")
public void doAfterThrowingTwo(Exception e) {
        System.out.println("异常通知,异常:"+e);
}
/**
 * 环绕通知 (用于权限判断)<br/>
 * 除方法名和参数名可修改外,其余不可变 <br/>
 * 需指明切入点 <br/>
 */
@Around("anyMethod()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

System.out.println("环绕通知 执行,进入方法...");

//获取被拦截的方法

Method method = ((MethodSignature)pjp.getSignature()).getMethod();

System.out.println("method:"+method.getName());

 

//获取拦截方法的参数

Object[] obj = pjp.getArgs(); 

for (Object object : obj) {

        System.out.println("AAA:"+object);

}
//必须执行这方法,如果后面有切面则先执行切面;
//如果不执行proceed(),则后面的方法和和切面都不执行
Object result = pjp.proceed(); //返回值,可以修改
System.out.println("退出方法...");
return result;
}
}
 

 
 * 解析:
 * @Pointcut("execution(* com.newer.service..*.*(..) ")
 * @Pointcut("execution(* com.newer.action..*.user*LoginOut())")
 * execution(* com.newer.service..*.*(..) <br/>
 * execution(1 com.newer.service..2.3(..) <br/>
 * 1. 表示返回值类型,例:java.lang.String,*号代表任何返回类型 ,!void表示必须有返回值
 * 2. 表示类,* 号代表对所有类拦截 <br/>
 * 3. 表示方法,* 号代表所有方法 <br/>
 * 4. service.. 这两个点代表可以对service下的子包进行拦截 <br/>
 * 5. (..) 表示方法的参数可以可无,一个也行,多个亦可,例如:(java.lang.String,..)
 * 
 * 注解引用切入点的写法
 * @Before("userLogin()")
 * @Before("userLogin() && userLoginOut()")
 * @Before("execution(* com.vveoss.examination.dailyExam.submitPaper(..))")
 

 
========================================================
 

 
第二步:xml方式的普通切面类,代码如下:
package com.newer.test;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 测试Spring AOP机制 <br/>
 * 使用xml方式配置
 * @author RSun
 * 2012-2-21上午12:07:17
 */
public class TestAOPXml {
/*** 注解定义前置通知(方法执行前执行) */
public void doAccessCheck() {
        System.out.println("xml-----------前置通知,是在方法前执行吗?");
}
/*** 后置通知(方法执行成功后执行) */
public void doAccessReturning() {
        System.out.println("xml-----------后置通知,是在方法后执行吗?");
}
/*** 最终通知 (finally块) */
public void doAfter() {
        System.out.println("xml-----------最终通知 执行...");
}
/**
 * 例外通知(异常通知catch块) <br/>
 * 后置通知不执行(最终通知在异常通知前执行) <br/>
 */
public void doAfterThrowing() {
        System.out.println("xml-----------异常通知,程序出现异常了吗?");
}
/**
 * 环绕通知 (用于权限判断)<br/>
 * 除方法名和参数名可修改外,其余不可变 <br/>
 */
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

System.out.println("xml-----------环绕通知 执行,进入方法...");

//必须执行这方法,如果后面有切面则先执行切面;

//如果不执行proceed(),则后面的方法和和切面都不执行

Object result = pjp.proceed();

System.out.println("xml-----------退出方法...");

return result;

}
}
 

 
========================================================
 

 
第三步: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: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">
<!-- 开启bean注解模式 -->
<context:annotation-config /> 
<!-- 扫描bean -->
<context:component-scan base-package="com.newer.service" />
<!-- 开启aop注解  -->
<aop:aspectj-autoproxy />
<!-- 切面交由Spring管理 -->
<bean id="testAop" class="com.newer.test.TestAOP" /> 

<!-- xml方式配置aop -->
<bean id="testAopXml" class="com.newer.test.TestAOPXml" />
<aop:config>

<aop:aspect id="asp" ref="testAopXml">

<!-- 定义切面 -->
<aop:pointcut id="mycut" expression="execution(* com.newer.service.impl.PersonServiceImpl.*(..))" />
<!-- 定义前置通知,关联切面和拦截方法doAccessCheck() -->
<aop:before pointcut-ref="mycut" method="doAccessCheck"/>
<!-- 定义后置通知 -->
<aop:after-returning pointcut-ref="mycut" method="doAccessReturning"/>
<!-- 异常通知 -->
<aop:after-throwing pointcut-ref="mycut" method="doAfterThrowing"/>
<!-- 最终通知 -->
<aop:after pointcut-ref="mycut" method="doAfter"/>
<!-- 环绕通知 -->
<aop:around pointcut-ref="mycut" method="doAround"/>

</aop:aspect>

</aop:config>
</beans>
 
 

 
总结:
  1. 配置好之后,可以使用junit测试,访问相关方法时会被触发。
  2. 需注意配置细节(只能拦截action、service和dao接口派生出来的方法)。