Spring(三)--AOP【面向切面编程】、通知类型及使用、切入点表达式
继承机制
封装方法
动态代理
……
3.情景举例
①数学计算器接口[MathCalculator]
int add(int i,int j);
int sub(int i,int j);
int mul(int i, int j);
public interface MathCaculator {
public int add(int i,int j);
public int sub(int i,int j);
public int mul(int i,int j);
public int div(int i,int j);
}
@Component
public class CacultorEasyImpl implements MathCaculator{
@Override
public void add(int i, int j) {
System.out.println("[日志],【参数:】"+i+","+j);
int result = i + j;
System.out.println("[日志],【参数:】"+i+","+j+"--"+result);
} @Override
public void sub(int i, int j) {
System.out.println("[日志],【参数:】"+i+","+j);
int result = i - j;
System.out.println("[日志],【参数:】"+i+","+j+"--"+result);
} @Override
public void mul(int i, int j) {
System.out.println("[日志],【参数:】"+i+","+j);
int result = i * j;
System.out.println("[日志],【参数:】"+i+","+j+"--"+result);
} @Override
public void div(int i, int j) {
System.out.println("[日志],【参数:】"+i+","+j);
int result = i / j;
System.out.println("[日志],【参数:】"+i+","+j+"--"+result);
}
}
<context:component-scan base-package="com.neuedu.aop"></context:component-scan>
③在简单实现的基础上让每一个计算方法都能够打印日志[LoginImpl]
private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test() {
CacultorEasyImpl bean = ioc.getBean(CacultorEasyImpl.class);
bean.add(10, 2);
bean.sub(10, 2);
bean.mul(10, 2);
bean.div(10, 2);
}
④缺陷
[1]手动添加日志繁琐,重复
[2]统一修改不便
[3]对目标方法本来要实现的核心功能有干扰,使程序代码很臃肿,不易于开发维护
⑤使用动态代理实现
[1]创建一个类,让这个类能够提供一个目标对象的代理对象
[2]在代理对象中打印日志
AOP概述
●AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论
●Spring的AOP既可以使用xml配置的方式实现,也可以使用注解的方式来实现!
5.在Spring中使用AOP实现日志功能
①Spring中可以使用注解或XML文件配置的方式实现AOP。
②导入jar包
com.springsource.net.sf.cglib -2.2.0.jar
com.springsource.org.aopalliance-1.0.0 .jar
com.springsource.org.aspectj.weaver-1.6.8 .RELEASE.jar
commons-logging-1.1.3. jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE. jar
③开启基于注解的AOP功能 < aop:aspectj-autoproxy />
<context:component-scan base-package="com.neuedu.aop"></context:component-scan>
<aop:aspectj-autoproxy/>
④声明一个切面类,并把这个切面类加入到 IOC容器中
在类上加以下两个注解
@Aspect :表示这是一个切面类
@Component :加入IOC容器
⑤在切面类中声明通知方法
[1] 前置通知:@Before
[2] 返回通知:@AfterReturning
[3] 异常通知:@AfterThrowing
[4] 后置通知:@After
[5] 环绕通知:@Around :环绕通知是前面四个通知的集合体!
@Component
@Aspect
public class CaculatorAspect { @Before(value="execution(public void com.neuedu.aop.RawCaculatorImpl.add(int, int))")
public void showBeginLog(){
System.out.println("日志开始");
} @After(value="execution(public void com.neuedu.aop.RawCaculatorImpl.add(int, int))")
public void showReturnLog(){
System.out.println("日志正常返回");
} @AfterThrowing(value="execution(public void com.neuedu.aop.RawCaculatorImpl.add(int, int))")
public void showExceptionLog(){
System.out.println("日志有错");
} @AfterReturning(value="execution(public void com.neuedu.aop.RawCaculatorImpl.add(int, int))")
public void showAfterLog(){
System.out.println("日志最终结束");
}
}
⑥被代理的对象也需要加入IOC容器
@Component
public class RawCaculatorImpl implements MathCaculator{ @Override
public void add(int i, int j) {
int result = i + j;
System.out.println(i+"+"+j+"="+result);
} @Override
public void sub(int i, int j) {
int result = i - j;
System.out.println(i+"-"+j+"="+result);
} @Override
public void mul(int i, int j) {
int result = i * j;
System.out.println(i+"*"+j+"="+result);
} @Override
public void div(int i, int j) {
int result = i / j;
System.out.println(i+"/"+j+"="+result);
}
}
Test 中 用 id 查找,通过强转,调用加减乘除四个方法
private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test() {
MathCaculator bean = (MathCaculator) ioc.getBean("rawCaculatorImpl");
bean.add(10, 2);
bean.sub(10, 2);
bean.mul(10, 2);
bean.div(10, 2);
}
@Component
@Aspect
public class CaculatorAspect { @Before(value="execution(public void com.neuedu.aop.RawCaculatorImpl.*(int, int))")
public void showBeginLog(){
System.out.println("日志开始");
} @After(value="execution(public void com.neuedu.aop.RawCaculatorImpl.*(int, int))")
public void showReturnLog(){
System.out.println("日志正常返回");
} @AfterThrowing(value="execution(public void com.neuedu.aop.RawCaculatorImpl.*(int, int))")
public void showExceptionLog(){
System.out.println("日志有错");
} @AfterReturning(value="execution(public void com.neuedu.aop.RawCaculatorImpl.*(int, int))")
public void showAfterLog(){
System.out.println("日志最终结束");
} }
如果方法中的参数类型不一致,可以用 (..) 代替 (int,int)
@Component
@Aspect
public class CaculatorAspect { @Pointcut(value="execution(* com.neuedu.aop.RawCaculatorImpl.*(..))")
public void showLog(){} @Before(value="showLog()")
public void showBeginLog(JoinPoint point){
Object[] args = point.getArgs();//获取参数
List<Object> asList = Arrays.asList(args);//转为list类型
Signature signature = point.getSignature();//获取签名
String name = signature.getName();//获取方法名字
System.out.println("【前置通知】目标方法名:"+name+",参数为:"+asList);
} @After(value="showLog()")
public void showReturnLog(){
System.out.println("【后置通知】日志最终返回");
} @AfterThrowing(value="showLog()",throwing="ex")
public void showExceptionLog(JoinPoint point,Exception ex){
System.out.println("【异常通知】异常信息为:"+ex.getMessage());
} @AfterReturning(value="showLog()",returning="result")
public void showAfterLog(JoinPoint point,Object result){
System.out.println("【返回通知】方法的返回值:"+result);
System.out.println();
}
}
参见第5章AOP细节:演示验证
1.任意参数,任意类型
2.任意返回值
3.用@PointCut注解统一声明,然后在其它通知中引用该统一声明即可!
需要注意的是:权限是不支持写通配符的,当然你可以写一个*表示所有权限所有返回值!
最详细的切入点表达式:
execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))
最模糊的切入点表达式:
@Pointcut(value= "execution(public int com.atguigu.aop.target.EazyImpl.add(int,int))")
public void myPointCut(){}
8.通知方法的细节
①在通知中获取目标方法的方法名和参数列表
[3]调用JoinPoint对象的getArgs()方法获取目标方法的实际参数列表
@Before(value="showLog()")
public void showBeginLog(JoinPoint point){
Object[] args = point.getArgs();//获取参数
List<Object> asList = Arrays.asList(args);//转为list类型
Signature signature = point.getSignature();//获取签名
String name = signature.getName();//获取方法名字
System.out.println("目标方法名:"+name+",参数为:"+asList);
System.out.println("日志开始");
}
@AfterReturning(value="showLog()",returning="result")
public void showAfterLog(JoinPoint point,Object result){
System.out.println("方法的返回值:"+result);
System.out.println("日志正常结束");
System.out.println();
}
@AfterThrowing(value="showLog()",throwing="ex")
public void showExceptionLog(JoinPoint point,Exception ex){
System.out.println("异常信息为:"+ex.getMessage());
System.out.println("日志有错");
}
10.环绕通知:@Around
1.环绕通知需要在方法的参数中指定JoinPoint的子接口类型ProceedingJoinPoint为参数
@Around(value="pointCut()")
public void around(ProceedingJoinPoint joinPoint){
}
2.环绕通知会将其他4个通知能干的,自己都给干了!
@Around(value="execution(public * com.neuedu.aop.RawCaculatorImpl.*(..))")
public Object showLog(ProceedingJoinPoint point){
Object[] args = point.getArgs();
List<Object> asList = Arrays.asList(args);
Signature signature = point.getSignature();//获取签名
String name = signature.getName();
Object result=null;
try {
try{
System.out.println("【前置通知】目标方法名:"+name+",参数为:"+asList);
result = point.proceed(args);
}finally{
System.out.println("【后置通知】日志最终返回");
}
System.out.println("【返回通知】方法的返回值:"+result);
} catch (Throwable e) {
System.out.println("【异常通知】异常信息为:"+e.getMessage());
}
System.out.println();
return result;
}
对于同一个代理对象,可以同时有多个切面共同对它进行代理。
@Component
@Aspect
@Order(value=20)
public class BAspect { @Around(value="execution(* com.neuedu.aop.RawCaculatorImpl.*(..))")
public Object showLog(ProceedingJoinPoint point){
Object[] args = point.getArgs();
List<Object> asList = Arrays.asList(args);
Signature signature = point.getSignature();//获取签名
String name = signature.getName();
Object result=null;
try {
try{
System.out.println("【前置】目标方法名:"+name+",参数为:"+asList);
result = point.proceed(args);
}finally{
System.out.println("【后置】日志最终返回");
}
System.out.println("【返回】方法的返回值:"+result);
} catch (Throwable e) {
System.out.println("【异常】异常信息为:"+e.getMessage());
}
System.out.println();
return result;
}
}
<!-- 将需要加载到IOC容器中的bean配置好 -->
<bean id="caculatorAspect" class="com.neuedu.aop.CaculatorAspect"></bean>
<bean id="bAspect" class="com.neuedu.aop.BAspect"></bean>
<bean id="rawCaculatorImpl" class="com.neuedu.aop.RawCaculatorImpl"></bean> <!-- 配置AOP,需要导入AOP名称空间 -->
<aop:config>
<!-- 声明切入点表达式 -->
<aop:pointcut expression="execution(* com.neuedu.aop.RawCaculatorImpl.*(..))" id="myPointCut"/>
<!-- 配置日志切面类,引用前面的类 ,通过order属性控制优先级-->
<aop:aspect ref="caculatorAspect" order="20">
<!-- 通过method属性指定切面类的切面方法,通过pointcut-ref指定切入点表达式 -->
<aop:before method="showBeginLog" pointcut-ref="myPointCut"/>
<aop:after method="showAfterLog" pointcut-ref="myPointCut"/>
<aop:after-returning method="showReturnLog" pointcut-ref="myPointCut" returning="result"/>
<aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="ex"/>
</aop:aspect>
<!-- 配置事务切面类,引用前面的类 -->
<aop:aspect ref="bAspect" order="25">
<aop:around method="showLog" pointcut-ref="myPointCut"/>
</aop:aspect> </aop:config>
需要知道的是:事务的管理是和AOP是有很大关系的,即声明式事务的底层是用AOP实现的!
Spring(三)--AOP【面向切面编程】、通知类型及使用、切入点表达式的更多相关文章
- Spring(三)AOP面向切面编程
原文链接:http://www.orlion.ga/205/ 一.AOP简介 1.AOP概念 参考文章:http://www.orlion.ml/57 2.AOP的产生 对于如下方法: pub ...
- Spring:AOP面向切面编程
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...
- Spring 08: AOP面向切面编程 + 手写AOP框架
核心解读 AOP:Aspect Oriented Programming,面向切面编程 核心1:将公共的,通用的,重复的代码单独开发,在需要时反织回去 核心2:面向接口编程,即设置接口类型的变量,传入 ...
- spring框架学习(三)——AOP( 面向切面编程)
AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...
- Spring框架 AOP面向切面编程(转)
一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...
- spring:AOP面向切面编程02
参考: https://blog.csdn.net/jeffleo/article/details/54136904 一.AOP的核心概念AOP(Aspect Oriented Programming ...
- Spring注解 - AOP 面向切面编程
基本概念: AOP:Aspect Oriented Programming,即面向切面编程 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式 前置通知(@Before):在目标 ...
- Spring的AOP面向切面编程
什么是AOP? 1.AOP概念介绍 所谓AOP,即Aspect orientied program,就是面向方面(切面)的编程. 功能: 让关注点代码与业务代码分离! 关注点: 重复代码就叫做关注点: ...
- Spring框架——AOP面向切面编程
简介 AOP练习 使用动态代理解决问题 Spring AOP 用AspectJ注解声明切面 前置后置通知 利用方法签名编写AspectJ切入点表达式 指定切面的优先级 基于XML的配置声明切面 Spr ...
- Spring之AOP(面向切面编程)_入门Demo
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可 ...
随机推荐
- vue数据绑定原理
一.定义 vue的数据双向绑定是基于Object.defineProperty方法,通过定义data属性的get和set函数来监听数据对象的变化,一旦变化,vue利用发布订阅模式,通知订阅者执行回调函 ...
- 配置ssh免密码登录——集群学习日记
度过了难熬的考试月时期之后,最近和小伙伴一起参加的的比赛进入了紧张的准备时期.在进行工作的时候,发现有很多基础的知识点,自己不是很清楚以及了解,所以在想,要不就边学习的时候边写下学习日记,以供自己后来 ...
- Python蜕变-2017-4-23
我的第一篇博客,这是试水练习.这次上的菜是Haporxy配置文件操作. <1> 上需求: 具体配置文件如下: global log 127.0.0.1 local2 daemon maxc ...
- HDOJ2004-成绩转换
Problem Description 输入一个百分制的成绩t,将其转换成对应的等级,具体转换规则如下:90~100为A;80~89为B;70~79为C;60~69为D;0~59为E; Input ...
- 故障公告:docker swarm集群“群龙无首”引发部分站点无法访问
今天傍晚 17:38-18:18 左右,由于 docker swarm 集群出现 "The swarm does not have a leader" 问题,造成博问.闪存.园子. ...
- HTMl课堂随笔
html: 1.超文本标记语言(Hyper Text Markup Lan) 2.不是一种编程语言,而是一种标记语言(Markup Language) 3.标记语言是一套标记标签(Markup Tag ...
- 最小生成树详解 prim+ kruskal代码模板
最小生成树概念: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边. 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里 ...
- mysql常用sql命令
一.连接MYSQL. 格式: mysql -h主机地址 -u用户名 -p用户密码 1.连接到本机上的MYSQL. 首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u roo ...
- 庖丁解牛——CY7C68013A开发框架
大家好,好久不见了,距离上次发文章都有两个多星期了,非常高兴同时也非常感谢你们能一直关注我.之前在公众号上收到网友的消息,其大概意思就是问我能不能出点USB干货,为此我就把第二篇--解密USB2.0数 ...
- echarts 柱状图,每根柱子显示不同颜色(随机显示和定制显示)
1,定制显示 option = { title: { text: '某地区降水量', subtext: '纯属虚构' }, tooltip: { trigger: 'axis' }, grid: { ...