前言:最近在复习spring特记录于此,欢迎大家交流指正 QQ:767872620
spring提供两种切面编程的使用方式:
(1)基于注解方式进行AOP开发
(2)基于xml配置方式进行AOP开发
一、环境配置
1.在配置文件中引入aop命名空间
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.0.xsd
2.导入jar包
http://www.springsources.org/downl
dist\spring.jar
lib\jakarta-commons\commons-logging.jar
使用aop另外导入:
lib\aspectj\aspectjweaver.jar和aspectjrt.jar
lib\cglib\cglib-nodep-2.2.2.jar
使用JSR-250中的注解,如@Resource
commons-annotations.jar
二、基于注解方式进行AOP开发
启动对@AspectJ注解的支持
<!-- 引入注解解释器 -->
<aop:aspectj-autoproxy/>
例子代码如下:
依然是熟悉的Person相关业务类
public interface PersonService {
public void save(String name);
public void update(String name,Integer id);
public String getPersonName();
public String getPersonName(Integer id);
}
package cn.itcast.service.imp;
import cn.itcast.service.PersonService;
public class PersonServiceBean implements PersonService {
public String getPersonName() {
System.out.println("我是getPersonName()");
return "xxx";
}
public String getPersonName(Integer id) {
System.out.println("我是getPersonName()");
return "xxx";
}
public void save(String name) {
throw new RuntimeException("我爱意外"); //用于测试意外通知
// System.out.println("我是save()");
}
public void update(String name, Integer id) {
System.out.println("我是update()");
}
}
切面代理类(注解实现):
package cn.itcast.service;
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;
/**
* 通过注解声明为切面
* @author Mars
*
*/
Aspect //将此类标记为拦截类(代理类)
public class MyInterceptor {
/**
*
* 1.拦截方法
* @Pointcut("execution(* cn.itcast.service..*.*(..)))")
* execution:执行业务方式是进行拦截
* *:返回值类型,*代表任何返回值类型
* cn.itcast.service:包名
* ..:对子包也进行拦截
* *:包下的什么类,*代表对所有类进行拦截
* *:指方法,*代表对所有的方法进行拦截
* ..:指方法的参数随意
*/
@Pointcut("execution(* cn.itcast.service.imp.PersonServiceBean.*(..))")
private void anyMethod(){} //声明一个切入点
/* *//**
* 2.前置通知
* 拦截方法后在执行业务方法之前进行执行
* 注解参数为切入点方法的名称,记得加括号
* 暂时不要参数
*//*
@Before("anyMethod()")
public void doAccessCheck(){
System.out.println("你好!我是前置通知,下面请业务方法闪亮登场");
}*/
/**
* 前置通知
* 获取执行业务方法的用户输入参数
* @Before("anyMethod() && args(username)")
* 拦截到的方法参数必须是一个,而且是必须是String的才会进入前置通知
* 其他的方法不执行前置通知方法
* 注解中的args(username)与public void doAccessCheck(String username)的参数必须一样
*
*/
@Before("anyMethod() && args username)")
public void doAccessCheck(String username){
System.out.println("前置参数:"+username+"你好!我是前置通知,下面请业务方法闪亮登场");
}
/* *//**
* 2.后置通知
* 拦截方法后在执行业务方法之后进行执行
* 注解参数为切入点方法的名称,记得加括号
* 暂时不要参数
*//*
@AfterReturning("anyMethod()")
public void doAfterReturning(){
System.out.println("业务方法执行完了,该我后置通知了!");
}*/
/**
* 后置通知
* 获取业务方法的返回值
* 说明:
* 注解参数returning="result"作用
* 1.获取业务方法返回值的类型为String类型
* 2.获取的返回值最为后置通知的参数传入后置方法
*/
@AfterReturning(pointcut="anyMethod()",returning="result")
public void doAfterReturning(String result){
System.out.println("业务方法执行完了,该我后置通知了!"+result);
}
/**
* 3.最终通知
* 后置通知执行完后执行最终通知
*/
@After("anyMethod()")
public void doAfter(){
System.out.println("后置通知完事了!是我最终通知");
}
/* *//**
* 4.意外通知
* 当执行业务方法时抛异常,执行意外通知
* 后置通知不会在被执行,前置通知、最终通知、意外通知都会被执行
*//*
@AfterThrowing("anyMethod()")
public void doAfterThrowing(){
System.out.println("意外通知");
}*/
/**意外通知
* 获取业务方法抛出的意外
*
*/
@AfterThrowing(pointcut="anyMethod()", throwing=" e")
public void doAfterThrowing( Exception e){
System.out.println("意外通知" + e);
}
/*
*
* 5.环绕通知
* 必须在环绕通知内部执行pjp.proceed();
* 否则后面的切面和业务方法不会被执行。
* 执行顺序:
*环绕通知->后面的切面(可以没有)-->目标对象的业务方法
*/
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
//if(){//判断用户是否有权限
System.out.println("进入环绕通知方法");
Object result = pjp.proceed();
System.out.println("退出环绕通知方法");
//}
return result;
}
}
配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy/>
<!-- 通过xml配置bean将拦截类交由spring管理 -->
<bean id="myInterceptor"class="cn.itcast.service.MyInterceptor"></bean>
<bean id="PersonService"class="cn.itcast.service.imp.PersonServiceBean"></bean>
</beans>
测试类(有点简陋):
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.service.PersonService;
public class SpringAOPTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception{
}
@Test public void interceptorTest(){
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService personservice = (PersonService)cxt.getBean("PersonService");
personservice.save("xxx");
// personservice.getPersonName(2);
}
}