0047 Spring的AOP入门基础--切面组件--通知--切入点
2017-03-21 20:33
435 查看
AOP的全称是Aspect Oriented Programming,面向切面编程。
切面是什么呢,就是一个Java类。之所以叫切面,就是说在调用其他一些类的方法的某个时候(之前,之后,抛异常等),调用这个类里的某个方法,因为要对很多类的很多方法进行相同的作用,就像一刀切一样。
aop涉及到三个要素:将哪个类的哪个方法,在什么时候,切入到哪个类的哪个方法上。依次对应了切面组件Aspect、通知Advice、切入点pointcut
看下面的示例,一个Controller组件,一个Service组件,两个Aspect组件,一个测试类,代码如下:
1. 用@Aspect声明TestLogB是一个切面组件
2. 在log方法前添加@Before注解,这是前置通知
3. 在@Before注解的属性中指定切入点,这里用的是方法限定表达式
测试类输出如下:
TestLogA是切面组件,切入点是Controller的方法前面 //TestLogA的log方法在Controller的testA()方法前调用
Controller的testA方法开始执行
TestLogB是切面组件,在调用Service方法前调用 //TestLogB的log方法在Service的testA()方法前调用
TestService的TestA方法开始执行
TestService的TestB方法开始执行 //因为TestLogB的log方法指定了只在testA前调用,在testB前不调用
TestLogA是切面组件,切入点是Controller的方法前面 //TestLogA的log方法在Controller的testB()方法前调用
Controller的testB方法开始执行
xml配置中先声明bean,再在aop:config的aop:aspect中指定为切面
或者用@Aspect注解指定
前置通知:@Before,方法调用之前
后置通知:@AfterReturning,方法正常返回
异常通知:@AfterThrowing,方法调用过程中出现异常
最终通知:@After,不管方法是正常返回还是出现异常,这个通知都会调用,因此必须这两种可能的情况
环绕通知:@Around,
方法限定表达式:
基本模式:execution([修饰符] 返回值类型 方法名(参数) [异常类型])。具体见Spring Reference 4.3.6版第223页
execution(public * * (..)):所有 的public方法
execution(* set(..)):以set打头的任意方法
execution( com.xyz.service.SomeService.(..):SomeService类下的任意方法
execution( com.xyz.service..(..)):service包下的任意类的任意方法
类型限定表达式:
within(com.xyz.service.):service包下的任意类下的任意方法,不包含子包
within(com.xyz.service..):包含子包
切面是什么呢,就是一个Java类。之所以叫切面,就是说在调用其他一些类的方法的某个时候(之前,之后,抛异常等),调用这个类里的某个方法,因为要对很多类的很多方法进行相同的作用,就像一刀切一样。
aop涉及到三个要素:将哪个类的哪个方法,在什么时候,切入到哪个类的哪个方法上。依次对应了切面组件Aspect、通知Advice、切入点pointcut
看下面的示例,一个Controller组件,一个Service组件,两个Aspect组件,一个测试类,代码如下:
//Controller组件 package net.sonng.controller; import javax.annotation.Resource; import net.sonng.service.TestService; import org.springframework.stereotype.Controller; @Controller public class TestController { @Resource private TestService ts; public void testA(){ System.out.println("Controller的testA方法开始执行"); ts.testA(); ts.testB(); } public void testB(){ System.out.println("Controller的testB方法开始执行"); } }
//Service组件 package net.sonng.service; import org.springframework.stereotype.Service; @Service public class TestService { public void testA (){ System.out.println("TestService的TestA方法开始执行"); } public void testB(){ System.out.println("TestService的TestB方法开始执行"); } }
//切面A package net.sonng.aspect; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component public class TestLogA { public void log(){ System.out.println("TestLogA是切面组件,切入点是Controller的方法前面"); } }
//切面B package net.sonng.aspect; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component @Aspect public class TestLogB { @Before("execution(* net.sonng.service.TestService.testA(..))") //方法限定表达式 public void log(){ System.out.println("TestLogB是切面组件,在调用Service方法前调用"); } }
//测试类 package net.sonng.test; import net.sonng.controller.TestController; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args){ ApplicationContext ac=new ClassPathXmlApplicationContext("ac.xml"); TestController tc=ac.getBean("testController",TestController.class); tc.testA(); tc.testB(); } }
采用xml配置,TestLogA的log方法在Controller组件的所有方法调用前调用
ac.xml配置如下:<mvc:annotation-driven /> <!-- 开启注解扫描 --> <context:component-scan base-package="net.sonng" /> <!-- 开启组件扫描 --> <aop:aspectj-autoproxy /> <!-- 开启AOP注解扫描 --> <bean id="log" class="net.sonng.aspect.TestLogA"></bean> <!-- 声明切面组件 --> <aop:config> <aop:aspect ref="log" > <!-- 以log为切面组件 --> <aop:before method="log" pointcut="within(net.sonng.controller.TestController)"/> </aop:aspect> <!-- aop:before是前置通知;method表示要调用的切面的方法;pointcut表示切入点,可以用类型/方法限定表达式 --> </aop:config> <!-- 这个xml配置表示:在net.sonng.controller.TestController下的所有方法被调用前,先调用net.sonng.aspect.TestLogA的log方法 -->
用注解配置,TestLogB的log方法在TestService的testA()方法调用前调用
注解配置见代码,要点如下:1. 用@Aspect声明TestLogB是一个切面组件
2. 在log方法前添加@Before注解,这是前置通知
3. 在@Before注解的属性中指定切入点,这里用的是方法限定表达式
测试类输出如下:
TestLogA是切面组件,切入点是Controller的方法前面 //TestLogA的log方法在Controller的testA()方法前调用
Controller的testA方法开始执行
TestLogB是切面组件,在调用Service方法前调用 //TestLogB的log方法在Service的testA()方法前调用
TestService的TestA方法开始执行
TestService的TestB方法开始执行 //因为TestLogB的log方法指定了只在testA前调用,在testB前不调用
TestLogA是切面组件,切入点是Controller的方法前面 //TestLogA的log方法在Controller的testB()方法前调用
Controller的testB方法开始执行
切面组件Aspect
切面组件一般是登录检查、日志记录、事务管理等xml配置中先声明bean,再在aop:config的aop:aspect中指定为切面
或者用@Aspect注解指定
通知advice
通知就是:在调用目标方法的什么时候调用切面组件的方法,可以是:前置通知:@Before,方法调用之前
后置通知:@AfterReturning,方法正常返回
异常通知:@AfterThrowing,方法调用过程中出现异常
最终通知:@After,不管方法是正常返回还是出现异常,这个通知都会调用,因此必须这两种可能的情况
环绕通知:@Around,
切入点
切入点就是要在哪些类的哪些方法上进行切入,可以限定一些类下的所有方法,或者不同类下的一些方法,或者指定类下的指定方法方法限定表达式:
基本模式:execution([修饰符] 返回值类型 方法名(参数) [异常类型])。具体见Spring Reference 4.3.6版第223页
execution(public * * (..)):所有 的public方法
execution(* set(..)):以set打头的任意方法
execution( com.xyz.service.SomeService.(..):SomeService类下的任意方法
execution( com.xyz.service..(..)):service包下的任意类的任意方法
类型限定表达式:
within(com.xyz.service.):service包下的任意类下的任意方法,不包含子包
within(com.xyz.service..):包含子包
相关文章推荐
- Spring4笔记----AOP的环绕通知、切面的优先级以及重用切入点定义
- Spring中基于aop命名空间的AOP 二(声明一个切面、切入点和通知)
- Spring -- AOP入门基础&基于Aspect的AOP通知用法
- Spring入门4 静态代理 动态代理 CGLIB AOP切入点切面 AOP注解
- JavaEE框架——Spring入门基础(控制反转Ioc和切面技术Aop)
- Spring入门 静态代理 动态代理 CGLIB AOP切入点切面 AOP注解
- Spring AOP 切面与通知【Spring 入门】
- [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.
- Spring in Action 入门之面向切面编程AOP
- 【spring】aop切面通知,日志处理
- spring 学习(1.3) 入门基础- AOP 实例
- spring 学习(1.2) 入门基础- AOP
- SpringAOP使用入门,如何对自定义的注解进行切面编程
- Spring AOP @AspectJ 入门基础
- Spring 切面 AOP基础 之三
- Spring 切面 AOP基础 之一
- spring 学习(1.4) 入门基础- AOP教程
- Spring-AOP的五种通知和切面的优先级、通知变量声明
- 5、AOP例子(切面,通知,切入点)
- Spring Aop之(二)--Aop 切面声明和通知