专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > ASP

Spring AOP 概念了解及@AspectJ支持

发布时间:2010-05-20 14:01:29 文章来源:www.iduyao.cn 采编人员:星星草
Spring AOP 概念理解及@AspectJ支持

Spring AOP 概念理解及@AspectJ支持   

2012-02-24 10:56:35 |  分类: Java | 字号   订阅

为了更好的理解Spring简介一文http://quicker.iteye.com/blog/670056 中的概念,下面通过一些示例来加以说明。

首先要理解代理模式:有静态代理和动态代理

有关代理模式相关文章:

http://quicker.iteye.com/blog/571494

http://quicker.iteye.com/blog/571493

下面先给出静态代理的代码。

Java代码  收藏代码
  1. public   interface  UserManager {  
  2.   
  3.     public   void  add(String name, String password);  
  4.     public   void  del(String id);  
  5.     public   void  modify( int  id ,String name, String password);  
  6. }  

 

Java代码  收藏代码
  1. public   class  UserManagerImpl  implements  UserManager {  
  2.   
  3.     public   void  add(String name, String password) {  
  4.   
  5.     }  
  6.   
  7.     public   void  del(String id) {  
  8.   
  9.     }  
  10.   
  11.     public   void  modify( int  id, String name, String password) {  
  12.   
  13.     }  
  14.   
  15. }  

 

Java代码  收藏代码
  1. public   class  UserManagerProxy  implements  UserManager {  
  2.   
  3.     private  UserManager userManager ;  
  4.     public   void  add(String name, String password) {  
  5.         check();  
  6.         userManager.add(name, password);  
  7.     }  
  8.   
  9.     public   void  del(String id) {  
  10.         check();  
  11.         userManager.del(id);  
  12.     }  
  13.   
  14.     public   void  modify( int  id, String name, String password) {  
  15.         check();  
  16.         userManager.modify(id, name, password);  
  17.     }  
  18.       
  19.     public   void  check(){  
  20.         System.out.println("check security" );  
  21.     }  
  22.       
  23.     public   void  setUserManager(UserManager userManager){  
  24.         this .userManager = userManager;  
  25.     }  
  26.   
  27.     public   static   void  main(String[] args) {  
  28.         UserManagerProxy proxy = new  UserManagerProxy();  
  29.         proxy.setUserManager(new  UserManagerImpl());  
  30.         proxy.add("name" , "pwd" );  
  31.     }  
  32. }  

 

上例中代理类控制在UserManagerImpl进行操作前对用户进行检查即check()方法。

 

那么下面用Spring Aop来实现。

配置步骤:

Java代码  收藏代码
  1. 通过示例,理解概念  
  2. 一、创建普通JAVA项目,加入用户自定义的包:  
  3. 包里有spring.jar,log4j-1.2 .15 .jar,commons-logging.jar  
  4. 二、拷贝log4j.properties和applicationContext.xml到src目录  
  5. 三、创建代码其中UserManager,UserManagerImpl类是用户管理接口及实现类  
  6.     MySecurityManager,MySecurityManagerImpl类是包含安全检查方法的接口及实现类。  
  7. 四、要启用@AspectJ 支持,@AspectJ 使用了Java 5 的注解,必须是Java 5 及后的才能使用。  
  8.     在applicationContext.xml加入:<aop:aspectj-autoproxy/>启用@AspectJ 支持。  
  9.     并在我们的用户自定义包中要加入aspectjrt.jar,aspectjweaver.jar,这两个包可以spring发布包  
  10.     的libaspectj下找到。  
  11. 五、声明一个切面:  
  12.     在类的定义前加入@Aspect ,并引入包 org.aspectj.lang.annotation.Aspect  
  13.     @Aspect 我们把用Aspect注解的类就叫切面  

 切面如:

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. import  org.aspectj.lang.annotation.Aspect;  
  4.   
  5. @Aspect   
  6. public   class  MySecurityManagerImpl  implements  MySecurityManager {  
  7.   
  8.     public   void  checkSecurity() {  
  9.         System.out.println("User security Check" );  
  10.     }  
  11.   
  12. }  

 

Java代码  收藏代码
  1. 六、声明一个切入点(pointcut)  
  2. 在前面我们提到,切入点决定了连接点关注的内容,使得我们可以控制通知什么时候执行。  
  3. Spring AOP只支持Spring bean的方法执行连接点。所以你可以把切入点看做是Spring bean上方法执行的匹配。  
  4. 一个切入点声明有两个部分:一个包含名字和任意参数的签名,还有一个切入点表达式,该表达式决定了我们关注那个方法的执行。  
  5. @AspectJ 注解风格的AOP中,一个切入点签名通过一个普通的方法定义来提供,  
  6. 并且切入点表达式使用@Pointcut 注解来表示(作为切入点签名的方法必须返回 void  类型)。   

  如:

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. import  org.aspectj.lang.annotation.Aspect;  
  4. import  org.aspectj.lang.annotation.Pointcut;  
  5. /*  
  6.  * 定义切面  
  7.  */   
  8. @Aspect   
  9. public   class  MySecurityManagerImpl  implements  MySecurityManager {  
  10.   
  11.     /*  
  12.      * 定义切入点,该方法返回值为void,该方法只是一个标识,就象配置文件的id  
  13.      * 切入点的内容是一个表达式,来描述切入哪些对象的哪些方法  
  14.      * ("excute (*add*(..))")切入点表达表示将要切入所有以add开头的方法,该方法可带任意个数的参数  
  15.      */   
  16.     @Pointcut  ( "execution (* add*(..))" )  
  17.     public   void  addAllMethod(){};  
  18.       
  19.     public   void  checkSecurity() {  
  20.         System.out.println("User security Check" );  
  21.     }  
  22.   
  23. }  

 

Java代码  收藏代码
  1. 七、声明通知  
  2. 通知是跟一个切入点表达式关联起来的,并且在切入点匹配的方法执行之前或者之后或者前后运行。   
  3. 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明过的切入点表达式。  
  4. 通知有:前置通知,后置通知,异常通知,最终通知,环绕通知  

 如:我们声明一个前置通知

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. import  org.aspectj.lang.annotation.Aspect;  
  4. import  org.aspectj.lang.annotation.Before;  
  5. import  org.aspectj.lang.annotation.Pointcut;  
  6. /*  
  7.  * 定义切面  
  8.  */   
  9. @Aspect   
  10. public   class  MySecurityManagerImpl  implements  MySecurityManager {  
  11.   
  12.     /*  
  13.      * 定义切入点,该方法返回值为void,该方法只是一个标识,就象配置文件的id  
  14.      * 切入点的内容是一个表达式,来描述切入哪些对象的哪些方法  
  15.      * ("excute (*add*(..))")切入点表达表示将要切入所有以add开头的方法,该方法可带任意个数的参数  
  16.      */   
  17.     @Pointcut  ( "execution (* add*(..))" )  
  18.     public   void  addAllMethod(){};  
  19.       
  20.       
  21.       
  22.     /*  
  23.      * 前置通知,在addAllMethod切入点所代表的方法前调用checkSecurity方法  
  24.      *   
  25.      */   
  26.     @Before  ( "addAllMethod()" )  
  27.     public   void  checkSecurity() {  
  28.         System.out.println("User security Check" );  
  29.     }  
  30.   
  31. }  

 

上面是分步的配置,下面我把整个配置好的项目代码列出来:

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. public   interface  UserManager {  
  4.   
  5.     public   void  add(String name, String password);  
  6.     public   void  del(String id);  
  7.     public   void  modify( int  id ,String name, String password);  
  8. }  

 

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. public   class  UserManagerImpl  implements  UserManager {  
  4.   
  5.     public   void  add(String name, String password) {  
  6.   
  7.         System.out.println("add method" );  
  8.     }  
  9.   
  10.     public   void  del(String id) {  
  11.         System.out.println("del method" );  
  12.     }  
  13.   
  14.     public   void  modify( int  id, String name, String password) {  
  15.         System.out.println("modify method" );  
  16.     }  
  17.   
  18. }  

 

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. public   interface  MySecurityManager {  
  4.   
  5.     public   void  checkSecurity();  
  6. }  

 

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. import  org.aspectj.lang.annotation.Aspect;  
  4. import  org.aspectj.lang.annotation.Before;  
  5. import  org.aspectj.lang.annotation.Pointcut;  
  6. /*  
  7.  * 定义切面  
  8.  */   
  9. @Aspect   
  10. public   class  MySecurityManagerImpl  implements  MySecurityManager {  
  11.   
  12.     /*  
  13.      * 定义切入点,该方法返回值为void,该方法只是一个标识,就象配置文件的id  
  14.      * 切入点的内容是一个表达式,来描述切入哪些对象的哪些方法  
  15.      * ("excute (*add*(..))")切入点表达表示将要切入所有以add开头的方法,该方法可带任意个数的参数  
  16.      */   
  17.     @Pointcut  ( "execution(* add*(..))" )  
  18.     public   void  addAllMethod(){};  
  19.       
  20.       
  21.     /*  
  22.      * 前置通知,在addAllMethod切入点所代表的方法前调用checkSecurity方法  
  23.      *   
  24.      */   
  25.     @Before ( "addAllMethod()" )  
  26.     public   void  checkSecurity() {  
  27.         System.out.println("User security Check" );  
  28.     }  
  29.   
  30. }  

 

配置文件:

Java代码  收藏代码
  1. <?xml version= "1.0"  encoding= "UTF-8" ?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"   
  4.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  5.         xmlns:aop="http://www.springframework.org/schema/aop"   
  6.         xmlns:tx="http://www.springframework.org/schema/tx"   
  7.         xsi:schemaLocation="  
  8.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  9.             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd   
  10.             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"   
  11. default -autowire= "byType"              
  12. >  
  13.       
  14.       
  15.     <aop:aspectj-autoproxy/>  
  16.     <bean id="userManager"   class = "com.lwf.aop.UserManagerImpl" ></bean>  
  17.     <bean id="mySecurityManager"   class = "com.lwf.aop.MySecurityManagerImpl" ></bean>  
  18. </beans>  

 

下面我们创建一个测试类:

 

Java代码  收藏代码
  1. package  com.lwf.aop;  
  2.   
  3. import  junit.framework.TestCase;  
  4.   
  5. import  org.springframework.context.ApplicationContext;  
  6. import  org.springframework.context.support.ClassPathXmlApplicationContext;  
  7.   
  8. public   class  Client  extends  TestCase{  
  9.   
  10.     public   void  testAop(){  
  11.         ApplicationContext ac = new  ClassPathXmlApplicationContext( "applicationContext.xml" );  
  12.         UserManager userManager = (UserManager)ac.getBean("userManager" );  
  13.         userManager.add("zhangshang" "123456" );  
  14.     }  
  15. }  

 

好了,上面的测试类,应该输出什么呢?

按照我们的静态代理,在调用add之前要先调用check方法,这里我们是先调用 checkSecurity()方法。

看下面的输出结果:

Java代码  收藏代码
  1. 2010 - 05 - 20   17 : 08 : 44 , 461  INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext @affc70 : display name [org.springframework.context.support.ClassPathXmlApplicationContext @affc70 ]; startup date [Thu May  20   17 : 08 : 44  CST  2010 ]; root of context hierarchy  
  2. 2010 - 05 - 20   17 : 08 : 44 , 633  INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from  class  path resource [applicationContext.xml]  
  3. 2010 - 05 - 20   17 : 08 : 45 , 055  INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - Bean factory  for  application context [org.springframework.context.support.ClassPathXmlApplicationContext @affc70 ]: org.springframework.beans.factory.support.DefaultListableBeanFactory @1c9a690   
  4. 2010 - 05 - 20   17 : 08 : 45 , 243  INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory @1c9a690 : defining beans [org.springframework.aop.config.internalAutoProxyCreator,userManager,mySecurityManager]; root of factory hierarchy  
  5. User security Check  
  6. add method  

 

显然调用了 checkSecurity()方法。

 

需要注意的是在切入点:@Pointcut ("execution(* add*(..))")这个地方一定要写对

是execution而不是execute,还有我们设置的是所有以add字符串开头的方法,注意前面的*与add之间要有空隔。因为最前面的*号代表所有的返回类型,而add*(..)中的*表示所有以add开头的方法名。

上面我们只定义了在add开头的方法前执行检查,那么我们也可以在del之前执行检查,使用||操作符,如下:

Java代码  收藏代码
  1. @Pointcut  ( "execution(* add(..)) || execution(* del(..))" )  

 

还要注意通知@Before("addAllMethod()"),不要写成@Before("addAllMethod")

还应该注意到切入点addAllMethod()这个方法是不会被执行的,只是起到一个标志作用。

 

 

现 在来总结一下:从静态代理到spring aop我们都实现了在操作用户之前调用方法进行用户检查。静态代理我们看成是OOP的处理,它需要代理类通过继承,是树型结构,要实现就要改变原来的树 型,即是有侵入性的。而spring aop则是横向的切入。没有改变原来的结构,是没有侵入性的。

AOP的没有侵入性的特性,是对OOP的一个补充。

 

对于常用的切入点表达式有:

Java代码  收藏代码
  1. 使用的最频繁的返回类型模式是*,它代表了匹配任意的返回类型。  
  2.  一个全限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。  
  3.   参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。  
  4.    模式(*)匹配了一个接受一个任何类型的参数的方法。 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。  

 

  • 任意公共方法的执行:

    execution(public * *(..))
  • 任何一个名字以“set”开始的方法的执行:

    execution(* set*(..))
  • AccountService 接口定义的任意方法的执行:

    execution(* com.xyz.service.AccountService.*(..))
  • 在service包中定义的任意方法的执行:

    execution(* com.xyz.service.*.*(..))
  • 在service包或其子包中定义的任意方法的执行:

    execution(* com.xyz.service..*.*(..))
  • 在service包中的任意连接点(在Spring AOP中只是方法执行):

    within(com.xyz.service.*)
  • 在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):

    within(com.xyz.service..*)
  • 实现了AccountService 接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):

    this(com.xyz.service.AccountService)

     

    'this'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。

  • 实现AccountService 接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):

    target(com.xyz.service.AccountService)

     

    'target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。

  • 任何一个只接受一个参数,并且运行时所传入的参数是Serializable  接口的连接点(在Spring AOP中只是方法执行)

    args(java.io.Serializable)

    'args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。

    请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)) : args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable 类型的参数时候匹配。

  • 目标对象中有一个 @Transactional  注解的任意连接点 (在Spring AOP中只是方法执行)

    @target(org.springframework.transaction.annotation.Transactional)

     

    '@target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。

  • 任何一个目标对象声明的类型有一个 @Transactional  注解的连接点 (在Spring AOP中只是方法执行):

    @within(org.springframework.transaction.annotation.Transactional)

     

    '@within'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。

  • 任何一个执行的方法有一个 @Transactional  注解的连接点 (在Spring AOP中只是方法执行)

    @annotation(org.springframework.transaction.annotation.Transactional)

     

    '@annotation'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。

  • 任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified  注解的连接点(在Spring AOP中只是方法执行)

    @args(com.xyz.security.Classified)

     

    '@args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。

  • 任何一个在名为'tradeService '的Spring bean之上的连接点 (在Spring AOP中只是方法执行):

    bean(tradeService)
  • 任何一个在名字匹配通配符表达式'*Service '的Spring bean之上的连接点 (在Spring AOP中只是方法执行):

    bean(*Service)

友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

  • ASP怎么隐藏表单

    ASP如何隐藏表单 <%if Cookies_Toy ="" then response.write "<a href='login.asp'>登录</a> <a href='reg.asp'>注册</a>" ...

  • 为何js调用css脚本后没效果

    为什么js调用css脚本后没效果 这个是css的脚本代码: body,ul,li{margin: 0; padding: 0; border: 0;} body {background: #f5f...

  • 怎么伪造post请求,求指点。

    如何伪造post请求,求指点。。。 要查询大批(也就几万个)运单的状态,那查询网站一次最多查24个,这一个个搞会搞死人的。。 有...

  • Asp.net_简略代码设置GridView自适应列宽不变形

    Asp.net_简单代码设置GridView自适应列宽不变形 动态绑定的GridView由于列数不固定,而列又太多(博主做的这个项目有150个左右的字段...

  • ASP.NET上实现AJAX注册提醒

    ASP.NET下实现AJAX注册提醒 Ajax全称是,主要是利用JavaScript实现异步的数据传输,首先说异步,异步是当前操作进行的时候,用...

  • aspnet_regiis装配出错:0x80070005 拒绝访问

    aspnet_regiis安装出错:0x80070005 拒绝访问 点击右边红色标题查看本文完整版:aspnet_regiis安装出错:0x80070005 拒绝访问安装...

  • 关于网站边框解决方法

    关于网站边框 像hao123这样的网站上的边框是着么弄的?背景图片吗?http://www.hao123.com 另外哪个素材网站有实用的这内素材 -----...

  • ! 多表分组查询统计

    求助!! 多表分组查询统计 高手们,帮帮忙! 用户表 D_user 为 ID Username GroupID 1 张三 2 2 李四 2 3 王五 ...

  • 在Paypal交付的同时,把表单的数据提交给数据库

    在Paypal提交的同时,把表单的数据提交给数据库 本帖最后由 liuyang2708 于 2012-11-20 23:14:54 编辑 在提交这个支付...

  • 虚拟目录上JavaScript不能正常执行

    虚拟目录下JavaScript不能正常执行 各位大侠好,我在同一台服务器上用两种方式部署同一个网站。 第一种方法:在IIS下直接建一个网站...

热门推荐: