Spring AOP四种实现方式(转载)

it2026-04-16  4

原文:Spring AOP四种实现方式Demo详解与相关知识探究

 

一、使用AOP的几种方式

1.经典的基于代理的AOP

2.@AspectJ注解驱动的切面

3.纯POJO切面

4.注入式AspectJ切面

 

二、Demo详解

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

包结构:

pom.xml:

 

[html] view plain copy print ? <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">      <modelVersion>4.0.0</modelVersion>        <groupId>com.springAOP</groupId>      <artifactId>springAOP</artifactId>      <version>0.0.1-SNAPSHOT</version>      <packaging>jar</packaging>        <name>springAOP</name>      <url>http://maven.apache.org</url>        <properties>          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>          <org.springframework.version>3.0.5.RELEASE</org.springframework.version>      </properties>          <dependencies>            <dependency>              <groupId>junit</groupId>              <artifactId>junit</artifactId>              <version>3.8.1</version>              <scope>test</scope>          </dependency>            <!-- Spring -->          <dependency>              <groupId>org.springframework</groupId>              <artifactId>spring-context</artifactId>              <version>${org.springframework.version}</version>          </dependency>            <!-- Spring AOP + AspectJ -->          <dependency>              <groupId>org.springframework</groupId>              <artifactId>spring-aop</artifactId>              <version>${org.springframework.version}</version>          </dependency>                    <dependency>              <groupId>org.aspectj</groupId>              <artifactId>aspectjrt</artifactId>              <version>1.8.9</version>          </dependency>                    <dependency>              <groupId>org.aspectj</groupId>              <artifactId>aspectjweaver</artifactId>              <version>1.8.9</version>          </dependency>            </dependencies>  </project>   下面开始正式的讲解:

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

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

 

[java] view plain copy print ? public interface Sleepable {      public void sleep();  }   (2)接口实现类,“Me”可以睡觉,“Me”就实现可以睡觉的接口。

 

[java] view plain copy print ? public class Me implements Sleepable{      public void sleep() {          System.out.println("\n睡觉!不休息哪里有力气学习!\n");      }  }   (3)Me关注于睡觉的逻辑,但是睡觉需要其他功能辅助,比如睡前脱衣服,起床脱衣服,这里开始就需要AOP替“Me”完成!解耦!首先需要一个SleepHelper类。因为一个是切入点前执行、一个是切入点之后执行,所以实现对应接口。

 

[java] view plain copy print ? public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice {        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {          System.out.println("睡觉前要脱衣服!");      }        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {          System.out.println("起床后要穿衣服!");      }    }   (4)最关键的来了,Spring核心配置文件application.xml配置AOP。

 

[html] view plain copy print ? <?xml version="1.0" encoding="UTF-8"?>  <beans xmlns="http://www.springframework.org/schema/beans"  <span style="white-space:pre">    </span>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  <span style="white-space:pre">    </span>xmlns:aop="http://www.springframework.org/schema/aop"  <span style="white-space:pre">    </span>xsi:schemaLocation="http://www.springframework.org/schema/beans  <span style="white-space:pre">    </span>http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  <span style="white-space:pre">    </span>http://www.springframework.org/schema/aop  <span style="white-space:pre">    </span>http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">          <!-- 定义被代理者 -->     <bean id="me" class="com.springAOP.bean.Me"></bean>          <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->     <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>          <!-- 定义切入点位置 -->     <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">          <property name="pattern" value=".*sleep"></property>     </bean>          <!-- 使切入点与通知相关联,完成切面配置 -->     <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">          <property name="advice" ref="sleepHelper"></property>                 <property name="pointcut" ref="sleepPointcut"></property>     </bean>          <!-- 设置代理 -->     <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">          <!-- 代理的对象,有睡觉能力 -->          <property name="target" ref="me"></property>          <!-- 使用切面 -->          <property name="interceptorNames" value="sleepHelperAdvisor"></property>          <!-- 代理接口,睡觉接口 -->          <property name="proxyInterfaces" value="com.springAOP.bean.Sleepable"></property>      </bean>        </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 print ? public class Test {      public static void main(String[] args){          @SuppressWarnings("resource")          //如果是web项目,则使用注释的代码加载配置文件,这里是一般的Java项目,所以使用下面的方式          //ApplicationContext appCtx = new ClassPathXmlApplicationContext("application.xml");          ApplicationContext appCtx = new FileSystemXmlApplicationContext("application.xml");          Sleepable me = (Sleepable)appCtx.getBean("proxy");          me.sleep();      }  }   执行结果:

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

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

 

[html] view plain copy print ? <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>   然后,在Test中,直接获取me对象,执行sleep方法,就可以实现同样的功能!

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

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

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

 

[java] view plain copy print ? @Aspect  public class SleepHelper{        public SleepHelper(){                }            @Pointcut("execution(* *.sleep())")      public void sleeppoint(){}            @Before("sleeppoint()")      public void beforeSleep(){          System.out.println("睡觉前要脱衣服!");      }            @AfterReturning("sleeppoint()")      public void afterSleep(){          System.out.println("睡醒了要穿衣服!");      }        }  

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

 

[java] view plain copy print ? //当抛出异常时被调用      public void doThrowing(JoinPoint point, Throwable ex)      {          System.out.println("doThrowing::method "                  + point.getTarget().getClass().getName() + "."                  + point.getSignature().getName() + " throw exception");          System.out.println(ex.getMessage());      }   (3)然后修改配置为:

 

[html] view plain copy print ?        <aop:aspectj-autoproxy />  <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->  <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>  <!-- 定义被代理者 -->  <bean id="me" class="com.springAOP.bean.Me"></bean>   (4)最后测试,一样的结果! [java] view plain copy print ? public class Test {      public static void main(String[] args){          @SuppressWarnings("resource")          //如果是web项目,则使用注释的代码加载配置文件,这里是一般的Java项目,所以使用下面的方式          //ApplicationContext appCtx = new ClassPathXmlApplicationContext("application.xml");          ApplicationContext appCtx = new FileSystemXmlApplicationContext("application.xml");          Sleepable me = (Sleepable)appCtx.getBean("me");          me.sleep();      }  }   3、使用Spring来定义纯粹的POJO切面(名字很绕口,其实就是纯粹通过<aop:fonfig>标签配置,也是一种比较简单的方式)。

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

 

[java] view plain copy print ? public class SleepHelper{        public void beforeSleep(){          System.out.println("睡觉前要脱衣服!");      }            public void afterSleep(){          System.out.println("睡醒了要穿衣服!");      }       }   (2)配置文件:

 

[html] view plain copy print ? <?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-3.0.xsd      http://www.springframework.org/schema/aop      http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">        <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->      <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>      <!-- 定义被代理者 -->      <bean id="me" class="com.springAOP.bean.Me"></bean>        <aop:config>          <aop:aspect ref="sleepHelper">              <aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))" />              <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))" />          </aop:aspect>      </aop:config>    </beans>  

(3)配置的另一种写法

 

[html] view plain copy print ? <aop:config>      <aop:aspect ref="sleepHelper">             <aop:pointcut id="sleepHelpers" expression="execution(* *.sleep(..))" />             <aop:before pointcut-ref="sleepHelpers" method="beforeSleep" />             <aop:after pointcut-ref="sleepHelpers" method="afterSleep" />                   </aop:aspect>  </aop:config>   五、AOP实现原理

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

 

 

转载于:https://www.cnblogs.com/liyuxinBlog/p/8394927.html

最新回复(0)