Spring 使用介绍(五)—— AOP(一)
一、简单使用:Hello World实例
1、定义目标类
public interface Hello {
void sayHello();
}
public class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("hello matt!");
}
}
2、定义切面支持类
public class HelloAspect {
public void beforeAdvice() {
System.out.println("****beforeAdvice");
} public void afterFinnallyAdvice() {
System.out.println("****afterFinnallyAdvice");
}
}
3、配置切面
<?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-4.2.xsd"> <!-- 目标类 -->
<bean id="hello" class="cn.matt.aop.HelloImpl"></bean> <!-- 切面支持类 -->
<bean id="helloAspect" class="cn.matt.aop.HelloAspect"></bean> <aop:config>
<!-- 切点 -->
<aop:pointcut id="pointcut" expression="execution(* cn.matt.aop..*.*(..))"/>
<!-- 切面 -->
<aop:aspect ref="helloAspect">
<aop:before pointcut-ref="pointcut" method="beforeAdvice"/>
<aop:after pointcut="execution(* cn.matt.aop..*.*(..))" method="afterFinnallyAdvice"/>
</aop:aspect>
</aop:config>
</beans>
4、测试
@Test
public void testSayHello() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
Hello hello = context.getBean(Hello.class);
hello.sayHello();
}
输出:
****beforeAdvice
hello matt!
****afterFinnallyAdvice
二、AOP XML配置
AOP定义必须放在<aop:config>标签下,该标签下可以有<aop:pointcut>、<aop:advisor>、<aop:aspect>标签,配置顺序不可变
AOP配置步骤:
1)声明切面支持bean(通过<bean>标签实例化支持类)
2)声明切面,引用切面支持bean(切面由<aop:aspect>标签指定,ref属性用来引用切面支持Bean)
3)声明切入点,有两种方式(注意:切入点也是bean)
i)使用<aop:pointcut>声明一个切入点Bean,该切入点可被多个切面共享
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* cn.javass..*.*(..))"/>
<aop:aspect ref="aspectSupportBean">
<aop:before pointcut-ref="pointcut" method="before"/>
</aop:aspect>
</aop:config>
ii)匿名切入点Bean,通过pointcut属性指定
<aop:config>
<aop:aspect ref="aspectSupportBean">
<aop:after pointcut="execution(* cn.javass..*.*(..))" method="afterFinallyAdvice"/>
</aop:aspect>
</aop:config>
4)声明通知,有五种:
i)前置通知 方法调用前调用
ii)后置返回通知 方法调用后且正常返回时调用
iii)后置异常通知 方法调用后且抛出异常时调用
iv)后置最终通知 方法调用后始终调用
v)环绕通知 可控制方法的执行过程,如决定方法是否执行,什么时候执行,执行时替换方法参数,执行后替换返回值等
注意:当method属性需要指定支持类的某个重载方法时,需要指定参数列表
具体实例如下:
目标接口及实现
public interface Hello {
void sayBefore(String str);
String sayAfterReturning(String str);
void sayAfterThrowing();
void sayAfterFinnally();
void sayAround(String str);
}
public class HelloImpl implements Hello {
@Override
public void sayBefore(String str) {
System.out.println("sayBefore " + str);
} @Override
public String sayAfterReturning(String str) {
System.out.println("sayAfterReturning " + str);
return "returning";
} @Override
public void sayAfterThrowing() {
System.out.println("sayAfterThrowing");
throw new RuntimeException("test exception!");
} @Override
public void sayAfterFinnally() {
System.out.println("sayAfterFinnally");
} @Override
public void sayAround(String str) {
System.out.println("sayAround " + str);
}
}
AOP支持类
public class HelloAspect {
public void beforeAdvice(String param) {
System.out.println("****beforeAdvice " + param);
} public void afterReturningAdvice(String retVal) {
System.out.println("****afterFinnallyAdvice " + retVal);
} public void afterThrowingAdvice(Exception ex) {
System.out.println("****afterThrowingAdvice " + ex.getMessage());
} public void afterFinnallyAdvice() {
System.out.println("****afterFinnallyAdvice ");
} public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("===========around before advice");
Object retVal = pjp.proceed(new Object[] {"replace"});
System.out.println("===========around after advice");
return retVal;
}
}
AOP配置
<!-- 目标类实例化 -->
<bean id="aopHello" class="cn.matt.aop.HelloImpl"></bean> <!-- aop支持类实例化 -->
<bean id="helloAspect" class="cn.matt.aop.HelloAspect"></bean> <!-- aop配置 -->
<aop:config>
<aop:aspect ref="helloAspect">
<!-- 前置通知(简单) -->
<aop:before pointcut="execution(* cn.matt.aop..*.sayHello(..))"
method="beforeAdvice"/>
<!-- 前置通知(复杂) -->
<aop:before pointcut="execution(* cn.matt.aop..*.sayBefore(..)) and args(param)"
method="beforeAdvice(java.lang.String)"
arg-names="param"/>
<!-- 后置返回通知 -->
<aop:after-returning pointcut="execution(* cn.matt.aop..*.sayAfterReturning(..))"
method="afterReturningAdvice"
arg-names="retVal"
returning="retVal"/>
<!-- 后置异常通知 -->
<aop:after-throwing pointcut="execution(* cn.matt.aop..*.sayAfterThrowing(..))"
method="afterThrowingAdvice"
arg-names="exception"
throwing="exception"/>
<!-- 后置最终通知 -->
<aop:after pointcut="execution(* cn.matt.aop..*.sayAfterFinnally(..))"
method="afterFinnallyAdvice"/>
<!-- 环绕通知 -->
<aop:around pointcut="execution(* cn.matt.aop..*.sayAround(..))"
method="aroundAdvice"/>
</aop:aspect>
</aop:config>
测试
public class HelloTest { private static Hello hello; static {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
hello = context.getBean(Hello.class);
} @Test
public void testSayBefore() {
hello.sayBefore("opjuy");
} @Test
public void testSayAfterReturning() {
hello.sayAfterReturning("opjuy");
} @Test(expected = RuntimeException.class)
public void testSayAfterThrowing() {
hello.sayAfterThrowing();
} @Test
public void testSayAfterFinnally() {
hello.sayAfterFinnally();
} @Test
public void testSayAround() {
hello.sayAround("around");
}
}
三、AOP注解配置
使用@AspectJ风格的注解配置,首先须添加如下配置:
<aop:aspectj-autoproxy />
具体使用步骤如下:
1)使用@Aspect将切面支持类声明为切面,并实例化bean
@Aspect()
public class Aspect{
……
}
<bean id="aspect" class="……Aspect"/>
2)使用@Pointcut+方法(方法必须是返回void类型)声明切入点
@Pointcut(value="切入点表达式", argNames = "参数名列表")
public void pointcutName(……) {}
3)声明通知
@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")
@AfterReturning(value="切入点表达式或命名切入点", pointcut="切入点表达式或命名切入点", argNames="参数列表参数名", returning="返回值对应参数名")
@AfterThrowing (value="切入点表达式或命名切入点", pointcut="切入点表达式或命名切入点", argNames="参数列表参数名", throwing="异常对应参数名")
@After (value="切入点表达式或命名切入点", argNames="参数列表参数名")
@Around (value="切入点表达式或命名切入点", argNames="参数列表参数名")
注意:
i)value和pointcut均可指定切入点表达式或命名切入点,如两者同时指定,则pointcut覆盖value
ii)使用命名切入点时,须指定切入点名及其参数,若无参数,括号也不可省略,如:
错误:@Before(value = "pointcut1")
正确:@Before(value = "pointcut1()")
正确:@Before(value = "pointcut2(param)", argNames = "param")
具体实例如下:
目标接口及实现,同xml配置实例
AOP支持类
@Aspect
public class HelloAspect { // 切点1
@Pointcut(value = "execution(* cn.matt.aop..*.sayHello(..))")
public void pointcut1() {} // 切点2
@Pointcut(value = "execution(* cn.matt.aop..*.sayBefore(..)) && args(param)", argNames = "param")
public void pointcut2(String param) {} // 前置通知(简单)
@Before(value = "pointcut1()")
public void beforeAdvice() {
System.out.println("****beforeAdvice");
} // 前置通知(复杂)
@Before(value = "pointcut2(param)", argNames = "param")
public void beforeAdvice(String param) {
System.out.println("****beforeAdvice " + param);
} // 后置返回通知
@AfterReturning(value = "execution(* cn.matt.aop..*.sayAfterReturning(..))", argNames = "retVal", returning = "retVal")
public void afterReturningAdvice(String retVal) {
System.out.println("****afterFinnallyAdvice " + retVal);
} // 后置异常通知
@AfterThrowing(value = "execution(* cn.matt.aop..*.sayAfterThrowing(..))", argNames = "ex", throwing = "ex")
public void afterThrowingAdvice(Exception ex) {
System.out.println("****afterThrowingAdvice " + ex.getMessage());
} // 后置最终通知
@After(value = "execution(* cn.matt.aop..*.sayAfterFinnally(..))")
public void afterFinnallyAdvice() {
System.out.println("****afterFinnallyAdvice ");
} // 环绕通知
@Around(value = "execution(* cn.matt.aop..*.sayAround(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("===========around before advice");
Object retVal = pjp.proceed(new Object[] {"replace"});
System.out.println("===========around after advice");
return retVal;
}
}
AOP配置
<!-- 目标类实例化 -->
<bean id="aopHello" class="cn.matt.aop.HelloImpl"></bean> <!-- aop支持类实例化 -->
<bean id="helloAspect" class="cn.matt.aop.HelloAspect"></bean> <!-- 开启aop注解支持 -->
<aop:aspectj-autoproxy/>
测试,同xml配置实例
参考:
第六章 AOP 之 6.1 AOP基础 ——跟我学spring3
第六章 AOP 之 6.2 AOP的HelloWorld ——跟我学spring3
第六章 AOP 之 6.3 基于Schema的AOP ——跟我学spring3
第六章 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3
Spring 使用介绍(五)—— AOP(一)的更多相关文章
- Spring 学习十五 AOP
http://www.hongyanliren.com/2014m12/22797.html 1: 通知(advice): 就是你想要的功能,也就是安全.事物.日子等.先定义好,在想用的地方用一下.包 ...
- Spring框架IOC和AOP介绍
说明:本文部分内容参考其他优秀博客后结合自己实战例子改编如下 Spring框架是个轻量级的Java EE框架.所谓轻量级,是指不依赖于容器就能运行的.Struts.Hibernate也是轻量级的. 轻 ...
- 46. Spring Boot中使用AOP统一处理Web请求日志
在之前一系列的文章中都是提供了全部的代码,在之后的文章中就提供核心的代码进行讲解.有什么问题大家可以给我留言或者加我QQ,进行咨询. AOP为Aspect Oriented Programming的缩 ...
- Spring框架入门之AOP
Spring框架入门之AOP 一.Spring AOP简单介绍 AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented ...
- Spring入门介绍
概述 下载地址:https://repo.spring.io/release/org/springframework/spring/ spring是开源的轻量级框架 spring核心的主要两部分 AO ...
- 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
聊一聊Spring是怎么将AOP应用到Bean的生命周期中的? 本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spr ...
- 23种设计模式之自定义Spring框架(五)
7,自定义Spring框架 7.1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao ...
- 转-Spring Framework中的AOP之around通知
Spring Framework中的AOP之around通知 http://blog.csdn.net/xiaoliang_xie/article/details/7049183 标签: spring ...
- [翻译]Spring框架参考文档(V4.3.3)-第二章Spring框架介绍 2.1 2.2 翻译--2.3待继续
英文链接:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/overview.ht ...
- [置顶] 深入浅出Spring(三) AOP详解
上次的博文深入浅出Spring(二) IoC详解中,我为大家简单介绍了一下Spring框架核心内容中的IoC,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming ...
随机推荐
- 图解Redis之数据结构篇——链表
前言 Redis链表为双向无环链表! 图解Redis之数据结构篇--简单动态字符串SDS提到Redis使用了简单动态字符串,链表,字典(散列表),跳跃表,整数集合,压缩列表这些数据结构 ...
- .NET开源项目 QuarkDoc 一款自带极简主义属性的文档管理系统
有些话说在前头 因为公司产品业务重构且功能拆分组件化,往后会有很多的接口文档需要留存,所以急需一款文档管理系统.当时选型要求3点: 1.不能是云平台上的Saas服务,整个系统都要在自己公司部署维护(数 ...
- 如何向微软 Docs 和本地化社区提交翻译贡献
Docs (docs.microsoft.com)是微软新版的文档网站,重新规划了各项技术栈的文档结构,看起来比 MSDN 可读性更好.虽然 Docs 提供了各种语言的版本,但大多是机器翻译,某些中文 ...
- 一次掌握 React 与 React Native 两个框架
此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React 与 React Native 结合学习的方法. 1. 软件开发语言与框架的学习本质 我 ...
- RPM包制作过程(一)
本机环境:centos7,64位 1. 首先安装工具,rpmbuild可能在rpmdevtools里已经包含 #yum install rpm-devel.x86_64 #yum install rp ...
- Python学习第十一篇——for 的本质及如何正确修改列表
假如现在有一个列表:magicians_list = ['mole','jack','lucy'],现在想通过一个函数来实现,在列表的每个元素前面加上“the Great”的字样.现在通过一个函数来实 ...
- 通过设置线程池的最小线程数来提高task的效率,SetMinThreads。
http://www.cnblogs.com/Charltsing/p/taskpoolthread.html task默认对线程的调度是逐步增加的,连续多次运行并发线程,会提高占用的线程数,而等若干 ...
- asp.net Json序列化
Json作为一种数据传输格式与标准被广泛的使用在项目开发中,可以说简直离不开它.那么怎么来生成JSON格式的数据就成了我们首先需要解决的问题这里我们使用.net. 首先是获取数据 public ban ...
- vue处理异步数据踩过的坑
在开发时,由于数据是异步的导致页面在render 时data是空值 出现报错和警告. 我是这么处理的 把data先写出一个空的完整结构.暂时是这么处理 或者用三元表达式进行赋值监听.data ?myd ...
- 关于windows注册表
Windows 注册表 应该是一个 数据库.里面包含操作系统以及在其上的软件配置信息和旗下的硬件配置信息,有点就是整体和全面,控制面包和gpedit.msc 组策略应该是抽象过后的注册表配置信息, W ...