Spring核心之二:AOP(Aspect Oriented Programming) --- 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

专业术语:

    1. Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
    2. Pointcut(切入点): 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
    3. Advice(通知/增强): 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
    4. Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
    5. Target(目标对象): 代理的目标对象
    6. Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程.
       spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入.
    7. 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理解和基于注解配置的更多相关文章

  1. 我的Spring学习记录(二)

    本篇就简单的说一下Bean的装配和AOP 本篇的项目是在上一篇我的Spring学习记录(一) 中项目的基础上进行开发的 1. 使用setter方法和构造方法装配Bean 1.1 前期准备 使用sett ...

  2. Spring学习记录(十四)---JDBC基本操作

    先看一些定义: 在Spring JDBC模块中,所有的类可以被分到四个单独的包:1.core即核心包,它包含了JDBC的核心功能.此包内有很多重要的类,包括:JdbcTemplate类.SimpleJ ...

  3. Spring学习记录(十)---使用FactoryBean配置Bean

    之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...

  4. HTTP协议学习---(十二)理解转发与重定向

    解释一 转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求---->web服务器接受此请求-->调用内部的一个方法在容 ...

  5. 我的Spring学习记录(四)

    虽然Spring管理这我们的Bean很方便,但是,我们需要使用xml配置大量的Bean信息,告诉Spring我们要干嘛,这还是挺烦的,毕竟当我们的Bean随之增多的话,xml的各种配置会让人很头疼. ...

  6. 我的Spring学习记录(五)

    在我的Spring学习记录(四)中使用了注解的方式对前面三篇做了总结.而这次,使用了用户登录及注册来对于本人前面四篇做一个应用案例,希望通过这个来对于我们的Spring的使用有一定的了解. 1. 程序 ...

  7. Spring学习记录(十三)---基于xml文件配置AOP

    上一篇讲了用注解配置AOP,现在讲用xml怎么配置AOP 其实逻辑是一样的,只是用xml的方法,要把这种逻辑写出来,告诉spring框架去执行. 例子:这里的例子和上一篇的例子一样.换成xml方式 / ...

  8. Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】

    Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版]  发表于 2018-04-24 |  随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请 ...

  9. Lua和C++交互 学习记录之二:栈操作

    主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3  参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...

随机推荐

  1. 操作系统篇-调用门与特权级(CPL、DPL和RPL)

    || 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言 在前两篇文章(<操作系统篇-浅谈实模式与保护模式>和<操作系统篇-分段机制与GDT|LDT>)中,我们提到 ...

  2. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  3. 在离线环境中发布.NET Core至Windows Server 2008

    在离线环境中发布.NET Core至Windows Server 2008 0x00 写在开始 之前一篇博客中写了在离线环境中使用.NET Core,之后一边学习一边写了一些页面作为测试,现在打算发布 ...

  4. MVC5+EF6+MYSQl,使用codeFirst的数据迁移

    之前本人在用MVC4+EF5+MYSQL搭建自己的博客.地址:www.seesharply.com;遇到一个问题,就是采用ef的codefirst模式来编写程序,我们一般会在程序开发初期直接在glob ...

  5. 隐马尔科夫模型python实现简单拼音输入法

    在网上看到一篇关于隐马尔科夫模型的介绍,觉得简直不能再神奇,又在网上找到大神的一篇关于如何用隐马尔可夫模型实现中文拼音输入的博客,无奈大神没给可以运行的代码,只能纯手动网上找到了结巴分词的词库,根据此 ...

  6. 用scikit-learn学习谱聚类

    在谱聚类(spectral clustering)原理总结中,我们对谱聚类的原理做了总结.这里我们就对scikit-learn中谱聚类的使用做一个总结. 1. scikit-learn谱聚类概述 在s ...

  7. C++随笔:.NET CoreCLR之GC探索(1)

    一直是.NET程序员,但是.NET的核心其实还是C++,所以我准备花 一点时间来研究CoreCLR和CoreFX.希望这个系列的文章能给大家带来 帮助. GC的代码有很多很多,而且结构层次对于一个初学 ...

  8. Visual Studio 2013 添加一般应用程序(.ashx)文件到SharePoint项目

    默认,在用vs2013开发SharePoint项目时,vs没有提供一般应用程序(.ashx)的项目模板,本文解决此问题. 以管理员身份启动vs2013,创建一个"SharePoint 201 ...

  9. 如何区别数据库删除语句drop与delete与truncate?

    1.delete:删除数据表中的行(可以删除某一行,也可以在不删除数据表的情况下删除所有行) 删除某一行:delete from 数据表名称 where 列名称=值: 删除所有行:delete*fro ...

  10. DB2重启数据库实例

    DB2重启数据库实例时,有时停止实例会失败,此时需要先确认没有应用链接数据库,然后再关闭数据库实例,并重新启动. 1.查看是否有活动的链接 命令:db2 list applications for d ...