Spring学习记录(十二)---AOP理解和基于注解配置
Spring核心之二:AOP(Aspect Oriented Programming) --- 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
专业术语:
- Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
- Pointcut(切入点): 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
- Advice(通知/增强): 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
- Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
- Target(目标对象): 代理的目标对象
- Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程.
spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入. - Proxy(代理): 一个类被AOP织入增强后,就产生一个结果代理类Aspect(切面): 是切入点和通知(引介)的结合
动态代理:AOP的核心是java的动态代理技术,比它更简单。
看一个例子
一个类有几个简单的方法
package com.atguigu.spring.aop.helloword; public class Calculator implements Calcul{ public int add(int i,int j){
return i+j;
};
public int sub(int i,int j){
return i-j;
};
public int div(int i,int j){
return i/j;
};
public int mul(int i,int j){
return i*j;
};
}
如果要你给每个方法都加上日志,好在执行的时候知道调用了哪个方法、什么参数和什么结果,那就得这样
package com.atguigu.spring.aop.helloword; public class Calculator implements Calcul{ public int add(int i,int j){
System.out.println("The method add begins with: ["+i+","+j+"]");
System.out.println("The method add ends with: "+(i+j));
return i+j;
};
public int sub(int i,int j){
System.out.println("The method sub begins with: ["+i+","+j+"]");
System.out.println("The method sub ends with: "+(i-j));
return i-j;
};
public int div(int i,int j){
System.out.println("The method div begins with: ["+i+","+j+"]");
System.out.println("The method div ends with: "+i/j);
return i/j;
};
public int mul(int i,int j){
System.out.println("The method mul begins with: ["+i+","+j+"]");
System.out.println("The method mul ends with: "+i*j);
return i*j;
};
}
看每一个方法的日志,都是很规范的,很整齐的。但就是太麻烦了,太重复了。而且要改日志的格式,那就得一个一个的改,这样肯定不行。应该要把日志提取出来,让它重复使用。思想如下:
package com.atguigu.spring.aop.helloword; public int Allmethod(Method method,int j,int j){
System.out.println("The method "+method+" begins with: ["+i+","+j+"]");
int result=method(i.j);
System.out.println("The method "+method+" ends with: "result); }
这样,代码就整洁多了,要改日志也只要改一次。其实这个例子不是很准确,好像是一种聚合式代理。学AOP,一定要先学动态代理
推荐一个视频,讲动态代理原理:http://www.imooc.com/learn/214
这个包含了学spring需要先学的各个知识:http://stamen.iteye.com/blog/1507535
AspectJ:java社区最完整最完善的AOP框架;
AspectJ支持的5种类型的通知注解:
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行
@AfterRunning:返回通知,在方法返回结果后执行
@AfterThrowing:异常通知,在方法抛出异常之后执行
@Around:环绕通知,围绕着方法执行
Spring也有自身的AOP框架。可以使用基于AspectJ注解或基于XMl配置的AOP。
注解方式:
1、除spring基本jar包,额外需要加入jar包:aopalliance、aspectj.weaver、aop.RELRESE、aspects.RELEASE
2、配置自动扫描
<!-- 自动扫描,加入IOC容器 -->
<context:component-scan base-package="com.atguigu.spring.aop.impl"></context:component-scan> <!-- 是Aspect注解起作用:自动为匹配的类生产代理对象 -->
<aop:aspect-autoproxy></aop:aspect-autoproxy>
3、创建接口和实现类
package com.atguigu.spring.aop.impl;
//接口
public interface Calculator { public int add(int i,int j);
public int sub(int i,int j);
public int div(int i,int j);
public int mul(int i,int j);
}
package com.atguigu.spring.aop.impl;
//实现类
import org.springframework.stereotype.Component;
//加入注解
@Component
public class CalculatorImpl implements Calculator{ public int add(int i,int j){
return i+j;
};
public int sub(int i,int j){
return i-j;
};
public int div(int i,int j){
return i/j;
};
public int mul(int i,int j){
return i*j;
}
}
创建日志切面:
package com.atguigu.spring.aop.impl; import org.springframework.stereotype.Component;
import org.springframework.test.context.transaction.BeforeTransaction; //吧这个类申明为一个切面:要把该类放入到IOC容器、再声明为一个切面
@Aspect
@Component
public class LogginfAspect {
//声明该方法是一个前置通知,在目标方法开始前执行
//@Before("excution(修饰符 + 返回类型 + 类名,去参数名)")
@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.add(int, int))");
public void befored(){
System.out.println("The method begins: ");
}
}
最后调用main方法
public class Main { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("application.xml");
Calculator cal = (Calculator) ctx.getBean(Calculator.class);
int result=cal.add(3,6);
System.out.println("result: "+result);
} }
结果:
若要获取类名,参数等,在切面改就行:
//吧这个类申明为一个切面:要把该类放入到IOC容器、再声明为一个切面
@Aspect
@Component
public class LogginfAspect {
//声明该方法是一个前置通知,在目标方法开始前执行
//@Before("excution(public + 全类名,去参数名)")
@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.add(int, int))");
public void beforedMethod(JoinPoint joinPoint){
String methodName=joinPoint.getSignature().getName();
List<Object> args = Arrays.arrays(joinPoint.getArgs())
System.out.println("The method "+ methodName +"begins: "+args);
}
}
结果:
@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.add(int, int))");
这句话,只是在add方法才有用,变成所有方法:把add改成*:
@Before("excution(public int com.atguigu.spring.aop.impl.CalculatorImpl.*(int, int))");
同样,还可以改成这样
@Before("excution(* int com.atguigu.spring.aop.impl.CalculatorImpl.*(int, int))");
@Before("excution(* com.atguigu.spring.aop.impl.CalculatorImpl.*(int, int))");(表示前面两个都是*)
注意:
对于后置通知
对于返回通知:
对于异常通知:
对于环绕通知,它的功能最强大,可以包含前面所以的通知,但并不意味着最常用
注意:如果有多个切面,有默认的先后执行顺序。可以用@Order(num)定义优先级,num越小,优先级越高。
注意:使用切入点,后面的切面就可以使用这个切点,写法更整洁。
如:前置通知写成:@Before("declareJointPointExpression()");
后置通知写成:@After("declareJointPointExpression()");
其他的同理。
再看一下笔记:
Spring学习记录(十二)---AOP理解和基于注解配置的更多相关文章
- 我的Spring学习记录(二)
本篇就简单的说一下Bean的装配和AOP 本篇的项目是在上一篇我的Spring学习记录(一) 中项目的基础上进行开发的 1. 使用setter方法和构造方法装配Bean 1.1 前期准备 使用sett ...
- Spring学习记录(十四)---JDBC基本操作
先看一些定义: 在Spring JDBC模块中,所有的类可以被分到四个单独的包:1.core即核心包,它包含了JDBC的核心功能.此包内有很多重要的类,包括:JdbcTemplate类.SimpleJ ...
- Spring学习记录(十)---使用FactoryBean配置Bean
之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...
- HTTP协议学习---(十二)理解转发与重定向
解释一 转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求---->web服务器接受此请求-->调用内部的一个方法在容 ...
- 我的Spring学习记录(四)
虽然Spring管理这我们的Bean很方便,但是,我们需要使用xml配置大量的Bean信息,告诉Spring我们要干嘛,这还是挺烦的,毕竟当我们的Bean随之增多的话,xml的各种配置会让人很头疼. ...
- 我的Spring学习记录(五)
在我的Spring学习记录(四)中使用了注解的方式对前面三篇做了总结.而这次,使用了用户登录及注册来对于本人前面四篇做一个应用案例,希望通过这个来对于我们的Spring的使用有一定的了解. 1. 程序 ...
- Spring学习记录(十三)---基于xml文件配置AOP
上一篇讲了用注解配置AOP,现在讲用xml怎么配置AOP 其实逻辑是一样的,只是用xml的方法,要把这种逻辑写出来,告诉spring框架去执行. 例子:这里的例子和上一篇的例子一样.换成xml方式 / ...
- Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】
Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版] 发表于 2018-04-24 | 随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请 ...
- Lua和C++交互 学习记录之二:栈操作
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
随机推荐
- Jade模板引擎让你飞
写在前面:现在jade改名成pug了 一.安装 npm install jade 二.基本使用 1.简单使用 p hello jade! 渲染后: <p>hello jade!</p ...
- MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信
MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...
- 标准产品+定制开发:专注打造企业OA、智慧政务云平台——山东森普软件,交付率最高的技术型软件公司
一.公司简介山东森普信息技术有限公司(以下简称森普软件)是一家专门致力于移动互联网产品.企业管理软件定制开发的技术型企业.公司总部设在全国五大软件园之一的济南齐鲁软件园.森普SimPro是由Simpl ...
- 02.SQLServer性能优化之---牛逼的OSQL----大数据导入
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 上一篇:01.SQLServer性能优化之----强大的文件组----分盘存储 http ...
- Android的Kotlin秘方(II):RecyclerView 和 DiffUtil
作者:Antonio Leiva 时间:Sep 12, 2016 原文链接:http://antonioleiva.com/recyclerview-diffutil-kotlin/ 如你所知,在[支 ...
- <程序员从入门到精通> -- How
定位 自己才是职业生涯的管理者,想清楚自己的发展路径: 远期的理想是什么?近期的规划是什么?今日的任务和功课又是什么? 今日之任务或功课哪些有助于近期之规划的实现,而近期之规划是否有利于远期之理想? ...
- grunt配置任务
这个指南解释了如何使用 Gruntfile 来为你的项目配置task.如果你还不知道 Gruntfile 是什么,请先阅读 快速入门 指南并看看这个Gruntfile 实例. Grunt配置 Grun ...
- 我的MYSQL学习心得(二) 数据类型宽度
我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 理解Session与Cookie
写在前面的话:Session和Cookie是非常有意思的两个概念,对于两者的管理可以处理的很复杂,但是无论如何,理解Session和Cookie的基本概念和发明初衷,对于问题的解决,大有裨益. === ...
- windows10简单试用(多图,连薛定谔的猫都杀死了)
为了大家看起来方便,我的截图都是gif的,比较小,但是颜色会有色差,相信大家不介意的 昨天windows10可以下载第一时间就下了玩玩 由于是技术预览,所以不打算替换之前的系统,只装在虚拟机里玩玩就好 ...