Spring面向切面编程(AOP)

匿名 (未验证) 提交于 2019-12-03 00:32:02

AOP术语

  • 通知(Advice)
    定义一个方法的业务逻辑

Spring切面可以应用5种类型的通知

  • 前置通知(Before):在目标方法被调用之前调用通知功能;
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关
    心方法的输出是什么;
  • 返回通知(After-returning):在目标方法成功执行之后调用通
    知;
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方
    法调用之前和调用之后执行自定义的行为。

  • 连接点(Join point)
    在方法级别上调用还是在其他,Spring只支持方法级别的连接点

  • 切点(Poincut)
    在目标类那些方法需要做AOP,如以update*开头的方法
    execution(* com.anyb.service.Impl.update(..))
  • 切面(Aspect):通知的集合类

Spring提供了4种类型的AOP支持

  • 基于代理的经典Spring AOP;
  • 纯POJO切面;
  • @AspectJ注解驱动的切面;
  • 注入式AspectJ切面(适用于Spring各版本)

Spring借助AspectJ的切点表达式语言来定义Spring切面

  • arg() 限制连接点匹配参数为指定类型的执行方法
  • @args() 限制连接点匹配参数由指定注解标注的执行方法
  • execution() 用于匹配是连接点的执行方法
  • this() 限制连接点匹配AOP代理的bean引用为指定类型的类
  • target 限制连接点匹配目标对象为指定类型的类
  • @target()限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解
  • within() 限制连接点匹配指定的类型
  • @within()限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里)
  • @annotation 限定匹配带有指定注解的连接点

    pom.xml

<properties>         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>         <jdk.version>1.8</jdk.version>         <!-- 定义spring版本 -->         <spring.version>4.3.2.RELEASE</spring.version>     </properties>     <dependencies>         <!-- spring包 begin -->         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-core</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-web</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-oxm</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-tx</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-jdbc</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-webmvc</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-aop</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-context-support</artifactId>             <version>${spring.version}</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-test</artifactId>             <version>${spring.version}</version>         </dependency>         <!-- spring包 end -->         <!-- aspectj start -->         <dependency>             <groupId>org.aspectj</groupId>             <artifactId>aspectjweaver</artifactId>             <version>1.8.9</version>         </dependency>         <!-- aspectj end -->         <!-- junit测试 begin -->         <dependency>             <groupId>junit</groupId>             <artifactId>junit</artifactId>             <version>4.12</version>             <scope>test</scope>         </dependency>         <!-- junit测试 end -->     </dependencies>

AOP使用annotation

切面类

package com.anyb.annotation.aspect;  import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut;  /**  * 该类为测试前置通知、后置通知和切面  * @author Administrator  *  */ @Aspect public class Audience {     /**      * @Aspect 定义一个切面      * @After 通知方法会在目标方法返回或抛出异常后调用      * @AfterReturning 通知方法会在目标方法返回成功,无异常后调用      * @AfterThrowing 通知方法会在目标方法抛出异常后调用      * @Before 通知方法会在目标方法调用之前执行      * @Around 通知方法会将目标方法封装起来 ,前面通知的集合      */      @Before("execution(* com.anyb.annotation.service.*Impl.update*(String)) && args(name)")     //execution(* com.anyb.service.*Impl.update*(String)) && args(name)     //String接收的参数类型,args(name)指定参数(name需要和方法befor1参数name匹配)     public void befor1(String name) {         System.out.println("Audience.befor1()  "+name);     }     /**      * 相同的切点表达式我们重复了四遍,这可真不是什么光彩的事情。      * @Pointcut注解能够在一个@AspectJ切面内定义可重用的切点      */     @Pointcut("execution(* com.anyb.annotation.service.*Impl.update*(..))")     public void pointcut() {}     //引用Pointcut,使用方法名()     @Before("pointcut()")     public void befor2() {         System.out.println("Audience.befor2()");     }     @AfterReturning("pointcut()")     public void afterReturning() {         System.out.println("Audience.afterReturning()");     }     @AfterThrowing("pointcut()")     public void afterThrowing() {         System.out.println("Audience.afterThrowing()");     } } 

目标类

package com.anyb.annotation.service;  import org.springframework.stereotype.Service;  @Service("service") public class ServiceImpl {     public String updateTest(String name) {         System.out.println("ServiceImpl.updateTest()");         return "SUCCESS";     } } 

配置类

package com.anyb.annotation.aspect;  import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;  import com.anyb.annotation.service.ServiceImpl;  @Configuration //标识该类为spring的配置类 @EnableAspectJAutoProxy //启动AspectJ自动代理 @ComponentScan(basePackageClasses= {SpringConfig.class,ServiceImpl.class}) //启动扫描 public class SpringConfig {     @Bean(name="audience")//让spring管理切面     public Audience getAudience() {         return new Audience();     } } 

测试类

package com.anyb.annotation.aspect;  import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import com.anyb.annotation.service.ServiceImpl;   @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes= {SpringConfig.class}) public class TestAspectJ_javaConfig {     @Autowired     private ServiceImpl impl;     @Test     public void testUpdate() {         String str = impl.updateTest("anyb");         System.out.println(str);     } } 

AOP使用xml

切面类

package com.anyb.xml.aspect;  public class Advice {     public void befor() {         System.out.println("Advice.befor()");     }     public void after() {         System.out.println("Advice.after()");     }     public void afterReturning() {         System.out.println("Advice.afterReturning()");     }     public void afterThrowing() {         System.out.println("Advice.afterThrowing()");     } } 

目标类

package com.anyb.xml.service;  import org.springframework.stereotype.Service;  @Service("service") public class ServiceImpl {     public String updateTest(String name) {         System.out.println("ServiceImpl.updateTest()"+name);         return "SUCCESS";     } } 

配置类xml

<beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns:mvc="http://www.springframework.org/schema/mvc"     xmlns:context="http://www.springframework.org/schema/context"     xmlns:aop="http://www.springframework.org/schema/aop"      xmlns:c="http://www.springframework.org/schema/c"     xmlns:p="http://www.springframework.org/schema/p"     xmlns:tx="http://www.springframework.org/schema/tx"     xsi:schemaLocation="http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans-4.3.xsd          http://www.springframework.org/schema/mvc          http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd          http://www.springframework.org/schema/context          http://www.springframework.org/schema/context/spring-context-4.3.xsd          http://www.springframework.org/schema/aop          http://www.springframework.org/schema/aop/spring-aop-4.3.xsd          http://www.springframework.org/schema/tx          http://www.springframework.org/schema/tx/spring-tx-4.3.xsd ">     <!-- 组件扫描 -->     <context:component-scan base-package="com.anyb.xml.service" />     <bean id="advice" class="com.anyb.xml.aspect.Advice" />     <!-- AOP的配置 -->     <aop:config>         <!-- 定义切面 -->         <aop:aspect ref="advice" >             <!-- 声明一个pointcut1切面 -->             <aop:pointcut id="pointcut1"              expression="execution(* com.anyb.xml.service.*Impl.update*(..))" />             <!-- 引用切点 -->             <aop:before method="befor" pointcut-ref="pointcut1" />             <aop:after-returning method="afterReturning"              pointcut="execution(* com.anyb.xml.service.*Impl.update*(..))"/>             <aop:after-throwing method="afterThrowing"              pointcut="execution(* com.anyb.xml.service.*Impl.update*(..))"/>             <aop:after method="after"             pointcut="execution(* com.anyb.xml.service.*Impl.update*(..))"/>         </aop:aspect>     </aop:config> </beans>

测试类

package com.anyb.xml.aspect;  import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import com.anyb.xml.service.ServiceImpl;  @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations= {"spring-application.xml"}) public class TestAdvice_xml {     @Autowired     private ServiceImpl impl;     @Test     public void testUpdate() {         String str = impl.updateTest("anyb");         System.out.println(str);     } } 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!