`
西瓜味的雪碧
  • 浏览: 4277 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Srping aop四种实现方式Demo详解与相关知识探究(转)

 
阅读更多

原文链接 :  http://blog.csdn.net/zhangliangzi/article/details/52334964

一、AOP相关概念

(1)AOP是什么?AOP与拦截器的区别?

太抽象的不说,如果你知道Struts2的拦截器,拦截器就是应用的AOP的思想,它用于拦截Action以进行一些预处理或结果处理。而Spring的AOP是一种更通用的模式,可以拦截Spring管理的Bean,功能更强大,适用范围也更广,它是通过动态代理与反射机制实现的。(更详细的解释可参看博客 http://blog.csdn.net/zhangliangzi/article/details/51648032 )

(2)使用AOP需要的一些概念。

1.通知(Advice)

通知定义了在切入点代码执行时间点附近需要做的工作。

Spring支持五种类型的通知:

Before(前)  org.apringframework.aop.MethodBeforeAdvice
After-returning(返回后) org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后) org.springframework.aop.ThrowsAdvice
Arround(周围) org.aopaliance.intercept.MethodInterceptor
Introduction(引入) org.springframework.aop.IntroductionInterceptor

2.连接点(Joinpoint)

程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法调用时、异常抛出时、方法返回后等等。

3.切入点(Pointcut)

通知定义了切面要发生的“故事”,连接点定义了“故事”发生的时机,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正则表达式来指定。

4.切面(Aspect)

通知、连接点、切入点共同组成了切面:时间、地点和要发生的“故事”。

5.引入(Introduction)

引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)。

6.目标(Target)

即被通知的对象,如果没有AOP,那么通知的逻辑就要写在目标对象中,有了AOP之后它可以只关注自己要做的事,解耦合!

7.代理(proxy)

应用通知的对象,详细内容参见设计模式里面的动态代理模式。

8.织入(Weaving)

把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器;

(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码;

(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术。

二、使用AOP的几种方式

1.纯POJO切面

2.注入式AspectJ切面

3.经典的基于代理的AOP

4.@AspectJ注解驱动的切面

三、Demo详解

在讲Demo之前,先把项目结构贴一下,我用的的一般的Java Project+Maven进行测试,用Web Project的小区别一会会说到。有一点很重要,jar依赖必须导入正确,我在测试过程中,很多bug都是因为依赖问题引起的,这里也贴一下。

包结构:


pom.xml:

 

[html] view plain copy
 
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.     <modelVersion>4.0.0</modelVersion>  
  4.   
  5.     <groupId>com.springAOP</groupId>  
  6.     <artifactId>springAOP</artifactId>  
  7.     <version>0.0.1-SNAPSHOT</version>  
  8.     <packaging>jar</packaging>  
  9.   
  10.     <name>springAOP</name>  
  11.     <url>http://maven.apache.org</url>  
  12.   
  13.     <properties>  
  14.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15.         <org.springframework.version>3.0.5.RELEASE</org.springframework.version>  
  16.     </properties>  
  17.   
  18.   
  19.     <dependencies>  
  20.   
  21.         <dependency>  
  22.             <groupId>junit</groupId>  
  23.             <artifactId>junit</artifactId>  
  24.             <version>3.8.1</version>  
  25.             <scope>test</scope>  
  26.         </dependency>  
  27.   
  28.         <!-- Spring -->  
  29.         <dependency>  
  30.             <groupId>org.springframework</groupId>  
  31.             <artifactId>spring-context</artifactId>  
  32.             <version>${org.springframework.version}</version>  
  33.         </dependency>  
  34.   
  35.         <!-- Spring AOP + AspectJ -->  
  36.         <dependency>  
  37.             <groupId>org.springframework</groupId>  
  38.             <artifactId>spring-aop</artifactId>  
  39.             <version>${org.springframework.version}</version>  
  40.         </dependency>  
  41.           
  42.         <dependency>  
  43.             <groupId>org.aspectj</groupId>  
  44.             <artifactId>aspectjrt</artifactId>  
  45.             <version>1.8.9</version>  
  46.         </dependency>  
  47.           
  48.         <dependency>  
  49.             <groupId>org.aspectj</groupId>  
  50.             <artifactId>aspectjweaver</artifactId>  
  51.             <version>1.8.9</version>  
  52.         </dependency>  
  53.       
  54.     </dependencies>  
  55. </project>  


下面开始正式的讲解:

 

1、经典的基于代理的AOP实现,以一个睡觉的例子实现。

(1)可睡觉的接口,任何可以睡觉的人或机器都可以实现它。

 

[java] view plain copy
 
  1. public interface Sleepable {  
  2.     public void sleep();  
  3. }  

(2)接口实现类,“Me”可以睡觉,“Me”就实现可以睡觉的接口。

 

 

[java] view plain copy
 
  1. public class Me implements Sleepable{  
  2.     public void sleep() {  
  3.         System.out.println("\n睡觉!不休息哪里有力气学习!\n");  
  4.     }  
  5. }  

3)Me关注于睡觉的逻辑,但是睡觉需要其他功能辅助,比如睡前脱衣服,起床脱衣服,这里开始就需要AOP替“Me”完成!解耦!首先需要一个SleepHelper类。因为一个是切入点前执行、一个是切入点之后执行,所以实现对应接口。

 

 

[java] view plain copy
 
  1. public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice {  
  2.   
  3.     public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {  
  4.         System.out.println("睡觉前要脱衣服!");  
  5.     }  
  6.   
  7.     public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {  
  8.         System.out.println("起床后要穿衣服!");  
  9.     }  
  10.   
  11. }  

(4)最关键的来了,Spring核心配置文件application.xml配置AOP。

 

 

[html] view plain copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. <span style="white-space:pre">    </span>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. <span style="white-space:pre">    </span>xmlns:aop="http://www.springframework.org/schema/aop"  
  5. <span style="white-space:pre">    </span>xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6. <span style="white-space:pre">    </span>http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7. <span style="white-space:pre">    </span>http://www.springframework.org/schema/aop  
  8. <span style="white-space:pre">    </span>http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">  
  9.      
  10.    <!-- 定义被代理者 -->  
  11.    <bean id="me" class="com.springAOP.bean.Me"></bean>  
  12.      
  13.    <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->  
  14.    <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>  
  15.      
  16.    <!-- 定义切入点位置 -->  
  17.    <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">  
  18.         <property name="pattern" value=".*sleep"></property>  
  19.    </bean>  
  20.      
  21.    <!-- 使切入点与通知相关联,完成切面配置 -->  
  22.    <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
  23.         <property name="advice" ref="sleepHelper"></property>         
  24.         <property name="pointcut" ref="sleepPointcut"></property>  
  25.    </bean>  
  26.      
  27.    <!-- 设置代理 -->  
  28.    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  29.         <!-- 代理的对象,有睡觉能力 -->  
  30.         <property name="target" ref="me"></property>  
  31.         <!-- 使用切面 -->  
  32.         <property name="interceptorNames" value="sleepHelperAdvisor"></property>  
  33.         <!-- 代理接口,睡觉接口 -->  
  34.         <property name="proxyInterfaces" value="com.springAOP.bean.Sleepable"></property>   
  35.    </bean>  
  36.       
  37. </beans>  

其中:

 

<beans>是Spring的配置标签,beans里面几个重要的属性:

xmlns:

是默认的xml文档解析格式,即spring的beans。地址是http://www.springframework.org/schema/beans;通过设置这个属性,所有在beans里面声明的属性,可以直接通过<>来使用,比如<bean>等等。一个XML文件,只能声明一个默认的语义解析的规范。例如上面的xml中就只有beans一个是默认的,其他的都需要通过特定的标签来使用,比如aop,它自己有很多的属性,如果要使用,前面就必须加上aop:xxx才可以。类似的,如果默认的xmlns配置的是aop相关的语义解析规范,那么在xml中就可以直接写config这种标签了。

xmlns:xsi:

是xml需要遵守的规范,通过URL可以看到,是w3的统一规范,后面通过xsi:schemaLocation来定位所有的解析文件。

xmlns:aop:

这个是重点,是我们这里需要使用到的一些语义规范,与面向切面AOP相关。

xmlns:tx:

Spring中与事务相关的配置内容。

(5)测试类,Test,其中,通过AOP代理的方式执行Me的sleep()方法,会把执行前、执行后的操作执行,实现了AOP的效果!

 

[java] view plain copy
 
  1. public class Test {  
  2.     public static void main(String[] args){  
  3.         @SuppressWarnings("resource")  
  4.         //如果是web项目,则使用注释的代码加载配置文件,这里是一般的Java项目,所以使用下面的方式  
  5.         //ApplicationContext appCtx = new ClassPathXmlApplicationContext("application.xml");  
  6.         ApplicationContext appCtx = new FileSystemXmlApplicationContext("application.xml");  
  7.         Sleepable me = (Sleepable)appCtx.getBean("proxy");  
  8.         me.sleep();  
  9.     }  
  10. }  

执行结果:

 



(6)通过org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator简化配置。

将配置文件中设置代理的代码去掉,加上:

 

[html] view plain copy
 
  1. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>  

然后,在Test中,直接获取me对象,执行sleep方法,就可以实现同样的功能!

 

通过自动匹配,切面会自动匹配符合切入点的bean,会被自动代理,实现功能!

2、更简单的方式,通过AspectJ提供的注解实现AOP。

(1)同样的例子,修改后的SleepHelper:

 

[java] view plain copy
 
  1. @Aspect  
  2. public class SleepHelper{  
  3.   
  4.     public SleepHelper(){  
  5.           
  6.     }  
  7.       
  8.     @Pointcut("execution(* *.sleep())")  
  9.     public void sleeppoint(){}  
  10.       
  11.     @Before("sleeppoint()")  
  12.     public void beforeSleep(){  
  13.         System.out.println("睡觉前要脱衣服!");  
  14.     }  
  15.       
  16.     @AfterReturning("sleeppoint()")  
  17.     public void afterSleep(){  
  18.         System.out.println("睡醒了要穿衣服!");  
  19.     }  
  20.       
  21. }  

 

(2)在方法中,可以加上JoinPoint参数以进行相关操作,如:

 

[java] view plain copy
 
  1. //当抛出异常时被调用  
  2.     public void doThrowing(JoinPoint point, Throwable ex)  
  3.     {  
  4.         System.out.println("doThrowing::method "  
  5.                 + point.getTarget().getClass().getName() + "."  
  6.                 + point.getSignature().getName() + " throw exception");  
  7.         System.out.println(ex.getMessage());  
  8.     }  

 

(3)然后修改配置为:

 

[html] view plain copy
 
  1.        <aop:aspectj-autoproxy />  
  2. <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->  
  3. <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>  
  4. <!-- 定义被代理者 -->  
  5. <bean id="me" class="com.springAOP.bean.Me"></bean>  


(4)最后测试,一样的结果!

[java] view plain copy
 
  1. public class Test {  
  2.     public static void main(String[] args){  
  3.         @SuppressWarnings("resource")  
  4.         //如果是web项目,则使用注释的代码加载配置文件,这里是一般的Java项目,所以使用下面的方式  
  5.         //ApplicationContext appCtx = new ClassPathXmlApplicationContext("application.xml");  
  6.         ApplicationContext appCtx = new FileSystemXmlApplicationContext("application.xml");  
  7.         Sleepable me = (Sleepable)appCtx.getBean("me");  
  8.         me.sleep();  
  9.     }  
  10. }  


3、使用Spring来定义纯粹的POJO切面(名字很绕口,其实就是纯粹通过<aop:fonfig>标签配置,也是一种比较简单的方式)。

 

(1)修改后的SleepHelper类,很正常的类,所以这种方式的优点就是在代码中不体现任何AOP相关配置,纯粹使用xml配置。

 

[java] view plain copy
 
  1. public class SleepHelper{  
  2.   
  3.     public void beforeSleep(){  
  4.         System.out.println("睡觉前要脱衣服!");  
  5.     }  
  6.       
  7.     public void afterSleep(){  
  8.         System.out.println("睡醒了要穿衣服!");  
  9.     }  
  10.      
  11. }  

(2)配置文件:

 

 

[html] view plain copy
 
  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" xmlns:aop="http://www.springframework.org/schema/aop"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  6.     http://www.springframework.org/schema/aop  
  7.     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">  
  8.   
  9.     <!-- 实例化目标对象类和切面类 -->  
  10.     <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>  
  11.     <bean id="me" class="com.springAOP.bean.Me"></bean>  
  12.   
  13.     <aop:config>  
  14.         <aop:aspect ref="sleepHelper">  <!-- 切面类 sleepHelper-->
  15. <!--  <aop:之前before、之后after... method="切面类中的方法" pointcut="切入的对象"/>  -->
  16.             <aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))" />  
  17.             <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))" />  
  18.         </aop:aspect>  
  19.     </aop:config>  
  20.   
  21. </beans>  

 

(3)配置的另一种写法

 

[html] view plain copy
 
  1. <aop:config>  
  2.     <!-- 切入点 -->
  3.     <aop:aspect ref="sleepHelper">  <!-- 切面类 sleepHelpers-->   
  4.           <!-- 要切入的对象 -->     
  5.            <aop:pointcut id="sleepHelpers" expression="execution(* *.sleep(..))" />  
  6.            
  7.  <!--  <aop:之前before、之后after... method="切面类中的方法" pointcut-ref="上面的切入的对象"/>  -->
  8.            <aop:before pointcut-ref="sleepHelpers" method="beforeSleep" /> <!-- 之前通知 -->
     
  9.            <aop:after pointcut-ref="sleepHelpers" method="afterSleep" />   <!-- 之后通知 -->
             
  10.        </aop:aspect>  
  11. </aop:config>  

 

 

五、AOP实现原理

学东西还是要深入进去的,推荐一篇网评还不错的博文,http://blog.csdn.net/moreevan/article/details/11977115/

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    SpringAop学习笔记以及实现Demo

    ### 四、Demo详解 本资料包中的四个Demo分别展示了Spring AOP的四种不同应用场景: 1. **经典代理模式Demo**:演示了如何通过CGLIB代理实现方法的拦截,以及在方法调用前后执行自定义操作。 2. **基于注解的AOP ...

    @AspectJ配置Spring AOP,demo

    **Spring AOP与@AspectJ配置详解** Spring AOP(面向切面编程)是Spring框架的一个重要组成部分,它提供了一种模块化和声明式的方式来处理应用程序中的横切关注点,如日志、事务管理等。在传统的面向对象编程中,...

    SpringAOP实现.docx

    AOP在Spring框架中的实现主要分为两种方式:使用Spring的API接口以及自定义类来实现。 1. **什么是AOP** AOP(Aspect Oriented Programming)是一种编程思想,是对传统的面向对象编程(OOP)的补充。在OOP中,我们...

    最简单的SpringAOP入门案例

    5. **代理模式**:Spring AOP通过代理模式实现切面功能,有JDK动态代理和CGLIB代理两种方式,前者针对实现了接口的类,后者则用于未实现接口的类。 通过这个简单的案例,你应该对Spring AOP有了初步的理解。随着...

    maven工程AOP实现demo

    ** Maven工程AOP实现Demo详解 ** 在Java开发中,Maven是一个不可或缺的构建工具,它可以帮助我们管理项目依赖、构建应用以及执行自动化任务。而AOP(Aspect Oriented Programming,面向切面编程)则是Spring框架的...

    Aop之AspectJ详解解读demo

    在"AopDemo-master"压缩包中,通常包含了一个简单的AspectJ示例项目,可能包括以下部分: 1. **源代码**:包含切面类(如LoggingAspect)和业务逻辑类(如Service类)。 2. **配置文件**:如Spring的XML配置文件,...

    spring+quartz demo

    【Spring + Quartz 框架整合详解】 Spring 和 Quartz 是两个在 Java 开发领域中非常重要的框架。Spring 是一个全面的、开源的应用框架,提供依赖注入(DI)、面向切面编程(AOP)以及用于简化企业级应用开发的其他...

    spring aop 示例

    **Spring AOP 知识点详解** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它允许我们通过分离关注点来简化应用程序开发。在传统的面向对象编程中,业务逻辑和系统服务(如...

    Spring实现自动代理Demo

    在Spring框架中,自动代理是一种重要的特性,它允许我们在不修改原有代码的情况下,为bean添加额外的功能,如事务管理、AOP(面向切面编程)等。本篇将深入探讨如何利用Spring实现自动代理,特别是关注`...

    Spring AOP demo

    基于注解与 XML 配置文件两种形式的 AOP demo。 基于 xml 配置文件的 aop 管理 ```xml &lt;!-- 配置切面的bean --&gt; &lt;bean id="loggingAspect" class="com.jas.aop.xml.LoggingAspect"/&gt; &lt;aop:config&gt; &lt;!...

    Spring整合CXF demo

    **Spring整合CXF详解** Spring框架与Apache CXF的整合是企业级Java应用中常见的实践,主要用于构建基于SOAP和RESTful服务。这个"Spring整合CXF demo"项目提供了一个直观的例子,帮助开发者理解如何在Spring环境中...

    Spring定时器配置详解(附demo)

    Spring提供了两种主要的定时任务实现方式:`TaskScheduler`和`TaskExecutor`,以及基于Quartz的`SpringIntegration`模块。其中,`TaskScheduler`和`TaskExecutor`适用于简单的定时任务需求,如间隔执行或周期性执行...

    Spring xml 方式配制的小demo

    **Spring XML配置详解** 在Java开发领域,Spring框架以其强大的依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称AOP)能力,成为了企业级应用开发的重要工具。本篇文章...

    Spring AOP注解案例及基本原理详解

    Spring AOP注解案例及基本原理详解 Spring AOP是基于AspectJ实现的,提供了强大的面向切面编程功能。通过使用注解,可以将横切逻辑与业务逻辑分离,从而提高代码的可维护性和可读性。 Aspect: 切面是一个类,负责...

    spring3.2.6struts2.3.15MyBatis3整合DEMO

    《Spring 3.2.6、Struts 2.3.15与MyBatis 3整合实战详解》 在Java Web开发领域,Spring、Struts和MyBatis是三大主流框架,它们各自承担着不同的职责,共同构建了一个强大的企业级应用开发环境。本DEMO以Spring ...

    shiro+spring的Demo

    《Shiro与Spring整合实战详解》 在Java Web开发领域,Apache Shiro和Spring框架的结合使用已经成为一种常见的安全解决方案。本示例项目"shiro+Spring的Demo"旨在展示如何将这两个强大的工具集整合,以实现高效、...

    Spring3最简单的demo

    《Spring3最简单的DEMO详解》 在Java开发领域,Spring框架无疑是最为重要的轻量级框架之一,它以其强大的依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)功能,极大地...

    Spring demo 2017-04-18

    本次我们将通过"Spring demo 2017-04-18"的实例,深入探讨Spring的几个重要知识点,包括Bean的自动装配、AOP(面向切面编程)、泛型依赖注入以及JDBC的两种实现方式。 1. **Bean的自动装配**: Spring的自动装配...

    spring+hibernate+mysql整合Demo

    【Spring+Hibernate+MySQL整合详解】 在Java Web开发中,Spring、Hibernate和MySQL是三个非常重要的组件。Spring作为一款全面的后端应用框架,提供了强大的依赖注入、AOP(面向切面编程)以及MVC(模型-视图-控制器...

    Spring+SpringMvc+Mybatis+Dubbo 小Demo

    《Spring+SpringMvc+Mybatis+Dubbo整合实践详解》 在现代企业级应用开发中,Spring、SpringMvc、Mybatis和Dubbo是常见的技术栈,它们各自在不同的层面上发挥着关键作用。本篇文章将深入探讨这四大框架的集成与应用...

Global site tag (gtag.js) - Google Analytics