注解实现AOP(获取输入及返回参数)

来源:互联网 发布:linux时钟中断 编辑:程序博客网 时间:2024/06/15 22:08

1.要利用spring aop,至少需要添加以下jar包

使用spring需要的jar
spring.jar 、commons-logging.jar

使用切面编程(AOP)需要的jar

aspectjrt.jar、aspectjweaver.jar、cglib-nodep-2.1_3.jar

使用JSR-250提供的注解,如@Resource,需要的jar

common-annotations.jar

2.使用spring 进行aop编程,首先我们要在Spring的配置文件中引入aop命名空间:

复制代码
1 <beans xmlns=http://www.springframework.org/schema/beans2 xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance3 xmlns:aop=http://www.springframework.org/schema/aop4 xsi:schemaLocation=”http://www.springframework.org/schema/beans5 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd6 http://www.springramework.org/schema/aop7 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”>8 9 </beans>
复制代码

当然我们在使用spring的时候,肯定会使用到spring ioc相关的内容,也需要加入命名空间对IOC部分的支持

3.使用注解方式来实现aop,首先需要在spring的配置文件中启动对@AspectJ注解的支持

<aop:aspectj-autoproxy/>

4.建立一个类,作为切面类,然后在切面类中依次添加切入点,前置通知,后置通知,例外通知,最终通知,环绕通知等:

完整的java文件:

复制代码
 1 package com.yangyang.aop; 2  3 import org.aspectj.lang.ProceedingJoinPoint; 4 import org.aspectj.lang.annotation.After; 5 import org.aspectj.lang.annotation.AfterReturning; 6 import org.aspectj.lang.annotation.AfterThrowing; 7 import org.aspectj.lang.annotation.Around; 8 import org.aspectj.lang.annotation.Aspect; 9 import org.aspectj.lang.annotation.Before;10 import org.aspectj.lang.annotation.Pointcut;11 12 //声明该类为一个切面13 @Aspect 14 public class MyInterceptor {15      //切入点要拦截的类16     @Pointcut("execution (* com.yangyang.service..*.*(..))")17     private void anyMethod(){} //声明一个切入点,切入点的名称其实是一个方法18 19     //前置通知(不需要获取输入参数)20     @Before("anyMethod()")//第一个参数为切入点的名称21     public void doAccessCheck(){22         System.out.println("前置通知");23     }24     25     //后置通知(不需要获取返回值)26     @AfterReturning("anyMethod()")27     public void doAfterReturning(){28         System.out.println("后置通知:");29     }30     31     //例外通知(不需要异常信息)32     @AfterThrowing("anyMethod()")33     public void doAfterThrowing(){34         System.out.println("例外通知");35     }36     37     //最终通知38     @After("anyMethod()")39     public void doAfter(){40         System.out.println("最终通知");41     }42     43     //环绕通知(特别适合做权限系统)44     @Around("anyMethod()")45     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{46         System.out.println("环绕通知进入方法");47         Object object=pjp.proceed();48         System.out.println("环绕通知退出方法");49         return object;50     }51     52 }
复制代码

5.建立供测试的业务方法:这里只列出实现:

复制代码
 1 package com.yangyang.service.impl; 2  3 import com.yangyang.service.PersonService; 4  5 public class PersonServiceImpl implements PersonService{ 6  7     @Override 8     public String getNameById(Long id) { 9         System.out.println("我是getNameById()方法");10         return "csy";11     }12 13     @Override14     public void save(String name) {15         throw new RuntimeException("故意抛出了异常,仅供测试");16     //    System.out.println("我是save()方法");17     }18 19     @Override20     public void update(String name, Long id) {21         System.out.println("我是update()方法");22     }23 24 }
复制代码

6.将业务service的bean以及切面的类加入spring管理,完整的配置文件如下:

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4         xmlns:context="http://www.springframework.org/schema/context" 5         xmlns:aop="http://www.springframework.org/schema/aop"     6         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 9  <!-- 加上aop的命名空间以及DTD验证 -->10  11  12      <aop:aspectj-autoproxy/><!-- 打开aop对@Aspectj的注解支持 ,相当于为注解提供解析功能-->13      14      <bean id="myInterceptor" class="com.yangyang.aop.MyInterceptor"></bean>15      16     <bean id="personService" class="com.yangyang.service.impl.PersonServiceImpl">17     </bean>18     19 </beans>
复制代码

7.编写单元测试,来测试aop是否成功实现。代码:

复制代码
1 @Test2     public void testSpringInterceptor() {3         ApplicationContext ctx=new ClassPathXmlApplicationContext("resources/beans.xml");4         PersonService personService=(PersonService)ctx.getBean("personService");5         personService.getNameById(1l);6         System.out.println("----------------------------------");7         personService.save("csy");8     }
复制代码

观察结果如下:

前置通知
环绕通知进入方法
我是getNameById()方法
后置通知:
最终通知
环绕通知退出方法
----------------------------------
前置通知
环绕通知进入方法
例外通知
最终通知

可以看出AOP编写成功了。

思考一个问题,如果我们希望获取在业务操作在使用aop的服务时得到相应的输入,返回值,以及异常信息,那么切面该怎么改呢:

只需要在各自通知的地方加入相应类型的参数即可:

复制代码
 1 package com.yangyang.aop; 2  3 import org.aspectj.lang.ProceedingJoinPoint; 4 import org.aspectj.lang.annotation.After; 5 import org.aspectj.lang.annotation.AfterReturning; 6 import org.aspectj.lang.annotation.AfterThrowing; 7 import org.aspectj.lang.annotation.Around; 8 import org.aspectj.lang.annotation.Aspect; 9 import org.aspectj.lang.annotation.Before;10 import org.aspectj.lang.annotation.Pointcut;11 12 //声明该类为一个切面13 @Aspect 14 public class MyInterceptor {15      //切入点要拦截的类16     @Pointcut("execution (* com.yangyang.service..*.*(..))")17     private void anyMethod(){} //声明一个切入点,切入点的名称其实是一个方法18 19     //前置通知(获取输入参数)20     @Before("anyMethod() && args(name)")//第一个参数为切入点的名称,第二个是测试获取输入参数,此处为string类型的,参数名称与方法中的名称相同,如果不获取输入参数,可以不要21     public void doAccessCheck(String name){22         System.out.println("前置通知:"+name);23     }24     25     //后置通知(获取返回值)26     @AfterReturning (pointcut="anyMethod()", returning="result")27     public void doAfterReturning(String result){28         System.out.println("后置通知:"+result);29     }30 31     //例外通知(获取异常信息)32     @AfterThrowing(pointcut="anyMethod()",throwing="e")33     public void doAfterThrowing(Exception e){34         System.out.println("例外通知:"+e);35     }36     37     //最终通知38     @After("anyMethod()")39     public void doAfter(){40         System.out.println("最终通知");41     }42     43     //环绕通知(特别适合做权限系统)44     @Around("anyMethod()")45     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{46         System.out.println("环绕通知进入方法");47         Object object=pjp.proceed();48         System.out.println("环绕通知退出方法");49         return object;50     }51     52 }
复制代码

同理执行单元测试,可以看到结果:

环绕通知进入方法
我是getNameById()方法
后置通知:csy
最终通知
环绕通知退出方法
----------------------------------
前置通知:csy
环绕通知进入方法
例外通知:java.lang.RuntimeException: 故意抛出了异常,仅供测试
最终通知

这样我们的功能就开发完了


原地址:http://www.cnblogs.com/shunyang/p/3300179.html

原创粉丝点击