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 ...
随机推荐
- node-webkit 环境搭建与基础demo
首先去github上面下载(地址),具体更具自己的系统,我的是windows,这里只给出windows的做法 下载windows x64版本 下载之后解压,得到以下东西 为了方便,我们直接在这个目录中 ...
- 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...
- ABP文档 - Mvc 视图
文档目录 本节内容: 简介 AbpWebViewPage 基类 简介 ABP通过nuget包Abp.Web.Mvc集成到Mvc视图里,你可以像往常那样创建常规的视图. AbpWebViewPage 基 ...
- 如何正确使用日志Log
title: 如何正确使用日志Log date: 2015-01-08 12:54:46 categories: [Python] tags: [Python,log] --- 文章首发地址:http ...
- android http 抓包
有时候想开发的时候想看APP发出的http请求和响应是什么,这就需要抓包了,这可以得到一些不为人知的api,比如还可以干些“坏事”... 需要工具: Fiddler2 抓包(点击下载) Android ...
- MyBatis基础入门--知识点总结
对原生态jdbc程序的问题总结 下面是一个传统的jdbc连接oracle数据库的标准代码: public static void main(String[] args) throws Exceptio ...
- linux应用调试技术之GDB和GDBServer
1.调试原理 GDB调试是应用程序在开发板上运行,然后在PC机上对开发板上得应用程序进行调试,PC机运行GDB,开发板上运行GDBServer.在应用程序调试的时候,pc机上的gdb向开发板上的GDB ...
- Collection集合
一些关于集合内部算法可以查阅这篇文章<容器类总结>. (Abstract+) Collection 子类:List,Queue,Set 增: add(E):boolean addAll(C ...
- 【干货分享】流程DEMO-费用报销
流程名: 费用报销 业务描述: 流程发起时,要选择需要关联的事务审批单,会检查是否超申请,如果不超申请,可以直接发起流程,如果超了申请,需要检查预算,如果预算不够,将不允许发起报销申请,如果预算够用, ...
- Java—恶心的java.lang.NumberFormatException解决
项目中要把十六进制字符串转化为十进制, 用到了到了Integer.parseInt(str1.trim(), 16):这个是不是后抛出java.lang.NumberFormatException异常 ...