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); } }
文章来源: Spring面向切面编程(AOP)