spring笔记--使用springAPI以及自定义类 实现AOP的一个例子
Spring的另一个重要思想是AOP,面向切面的编程,它提供了一种机制,可以在执行业务前后执行另外的代码,Servlet中的Filter就是一种AOP思想的体现,下面通过一个例子来感受一下. 假设我们现在需要在针对数据库进行CRUD操作时添加一组日志,即在执行CRUD方法前后分别加上一句话,实现简单的面向切面编程的功能.我用到的是spring4,在配置文件上较之之前的版本可能有些不同. 使用springAPI来实现AOP,除了spring必不可少的核心jar包,还需要两个jar包需要导入:
并且配置文件的头文件也需要略作修改,需要加入aop的命名空间(namespace),详见下面实例中的beans.xml. UserService类(省略数据库操作代码,只做简单的打印来模拟): public class UserService {
void add(){
System.out.println("添加用户");
}
delete(){
System.out.println("删除用户" update(){
System.out.println("修改用户" search(){
System.out.println("查询用户");
}
}
Log类(在执行增删改查方法前执行): class Log implements MethodBeforeAdvice{
/***
* method:被调用的方法对象
* arg1:被调用的方法的参数
* target:被调用方法的目标对象
*/
@Override
before(Method method,Object[] arg1,Object target)
throws Throwable {
System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被执行");
}
}
AfterLog类(在执行增删改查方法后执行): class AfterLog AfterReturningAdvice{
* returnValue:返回值类型
* method:被调用的方法对象
* arg1:被调用的方法的参数
* target:被调用方法的目标对象
afterReturning(Object returnValue,Method method,Object[] args,Object target) Throwable {
System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被执行成功,返回值是"+returnValue);
}
spring配置文件(beans.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
bean id="userService" class="com.wang.service.UserService"></bean="log"="com.wang.log.Log"="afterlog"="com.wang.log.AfterLog"aop:config<!--"*"为通配符表示所有方法,第一个* 表示任意返回值 第二个*表示所有方法
".."表示任意个数的参数 -->
aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>
aop:advisor advice-ref pointcut-ref/>
</>
beans>
测试代码testDemo: @Test
test1(){
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
UserService userService=(UserService)context.getBean("userService");
userService.add();
userService.search();
}
运行测试可以看到控制台的打印结果:
在配置文件中,我们看到了一些这样的代码: "*"为通配符表示所有方法
".."表示任意个数的参数 >
我们来介绍几个AOP的相关概念,这个就比较好理解了: @H_661_403@简而言之:"切入点"负责往"什么地方"插入代码,"通知"负责插入"什么代码". ? SpringAOP将公共的业务(如日志,安全)和领域业务结合,当执行领域业务时候把公共业务加进来,实现公共业务的重复利用,使得领域业务功能更加纯粹,程序员可以专注于领域业务. 当然除了使用springAPI,我们也可以通过自定义的类,即不需要实现任何借口或继承任何类,的方式来实现上述功能: 只需要一个Log类: Log {
before(){
System.out.println("执行方法前");
}
after(){
System.out.println("执行方法后");
}
}
修改配置文件beans.xml中的<aop-config>为: >
aop:aspect ref="log"="execution(* com.wang.service.UserService.*(..))"/>
aop:before method="before"aop:after ="after"aop:aspect>
>
执行上面的测试代码,打印出的结果是:
?其实这种配置方式还可以用注解来完成,下面介绍一下使用注解的方式,顺带讲一个环绕方法,它和before和after一样,不过是在某一个方法前后都会执行的代码: Log类: @Aspect
Log {
@Before("execution(* com.wang.service.*.*(..))")
);
}
@After("execution(* com.wang.service.*.*(..))");
}
@Around("execution(* com.wang.service.*.*(..))"public Object around(ProceedingJoinPoint pjp) Throwable{
System.out.println("环绕前");
System.out.println("签名:"+pjp.getSignature());
//执行目标方法
Object proceed = pjp.proceed();
System.out.println("环绕后");
return proceed;
}
在beans.xml中,只需要将<aop-config>修改为一行代码: >
<aop:aspectj-autoproxy/>
>
打印结果如下,读者自行理解,这里对于around不再解释:
如果希望在before和after方法中得到当前执行方法的方法名或者参数的话,可以在bofore或者after方法中加一个参数,就是上面around方法中的参数, 获得方法名:String methodName=pjp.getSignature().getName(); 获得方法参数列表:List<Object> list=Arrays.toList(pjp.getArgs()); Spring支持5种类型的通知注解: @Before:前置通知,在方法执行前执行 @After:后置通知,在方法执行后执行(此注解标注的方法无法得到方法的返回值) @AfterRunning:返回通知,在方法返回结果之后执行(此注解标注的方法,可以获取到方法的返回值) @AfterThrowing:异常通知,在方法抛出异常后执行 @Around:环绕通知,问绕着方法执行(环绕通知必须要有ProceedingJoinPoint类型的参数,且必须要有返回值,见上面). (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |