今天主要是利用aop技术追加service的响应时间的计算和异常的日志记录。

AOP

  AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。

  AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程中的步骤进行抽象,从而获得步骤之间的逻辑划分。

  面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面

    1.面向切面编程提供声明式事务管理 **

    
2.spring支持用户自定义的切面**

特点:在不修改系统业务逻辑的前提下,给系统追加功能。

AOP核心概念

  • 1、横切关注点

  对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

  • 2、切面(aspect)

  类是对物体特征的抽象,切面就是对横切关注点的抽象

  • 3、连接点(joinpoint)

  被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

  • 4、切入点(pointcut)

  对连接点进行拦截的定义

  • 5、通知(Advice):

  在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类

型,其中包括"around"、"before”和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

  • 6、目标对象(Target):

  就是那些即将切入切面的对象,也就是那些被通知的对象。

  • 7、代理对象(Proxy):

  将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

  • 8、织入(weave)

  将切面应用到目标对象并导致代理对象创建的过程

  • 9、引入(introduction)

  在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

表达式:三种

AspectJ类型匹配的通配符:

   :匹配任何数量字符;

  ..:(两个点)匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。

  **+ **:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

  • 方法限定表达式:execution

为某个组件的部分方法追加功能

  • execution(修饰符? 返回类型 方法名(参数) 抛出异常?)

匹配所有以add开头的方法

    execution(* add*(..))

匹配UserService组件下所有的方法

execution(* cn.tedu.service.UserService.*(..))

匹配的service下所有组件的所有方法

execution(* cn.tedu.service.*.*(..))

匹配的service包及子包中的所有方法

execution(* cn.tedu.service..*.*(..))

案例:

@Before execution(* cn.tedu.cloudnote.service..*.*(..))
  • 类级限定表达式:within

匹配UserService组件下的所有方法

within(cn.tedu.cloudnote.service.UserService)

匹配到service包下所有类的所有方法

within(cn.tedu.cloudnote.service.*)

匹配到service包及子包下的所有类的所有方法

within(cn.tedu.cloudnote.service..*)
  • bean限定表达式:bean(id名)

匹配userService组件的所有方法

bean(userService)

匹配所有以service结尾的组件的所有方法

bean(*Service)
@Bfore("bean(userController)")

通知(Advice)类型

  为了符合现实的各种需求,通知类型提供了5种,可以对目标方法进行全方位处理;

  • Before advice:在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。

  ApplicationContext中在aop:aspect里面使用aop:before元素进行声明。

  • After advice:当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

  ApplicationContext中在aop:aspect里面使用aop:after元素进行声明。

  • After returnadvice:在某连接点正常完成后执行的通知,不包括抛出异常的情况。

  ApplicationContext中在aop:aspect里面使用aop:after-returning元素进行声明。

  • Around advice:包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的

    行为,也可以选择不执行。

  ApplicationContext中在aop:aspect里面使用aop:around元素进行声明。

  • Afterthrowing advice:在方法抛出异常退出时执行的通知。

  ApplicationContext中在aop:aspect里面使用aop:after-throwing元素进行声明。

AOP 代理

OP支持2种代理,Jdk的动态代理和CGLIB实现机制。

  Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

  •   1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

  •   2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

二者区别:

  Jdk基于接口实现:JDK动态代理对实现了接口的类进行代理。

  CGLIB基于继承:CGLIB代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以目标类最好不要使用final声明。

  通常情况下,鼓励使用jdk代理,因为业务一般都会抽象出一个接口,而且不用引入新的东西。如果是遗留的系统,以前没有实现接口,那么只能使用CGLIB。

AOP配置

Spring AOP配置有两种风格:

  XML风格 = 采用声明形式实现Spring AOP

  AspectJ风格 = 采用注解形式实现Spring AOP

XML风格

<!-- com.tedu.cloudnote.aspect.LoggerBean为类名 -->
<bean id="loggerBean" class="com.tedu.cloudnote.aspect.LoggerBean">
</bean>
<aop:config>
<!-- 通过ref关联组建类 -->
<aop:aspect ref="loggerBean">
<!-- 通过method指定处理方法,logController为方法名 -->
<aop:before method="logController"
pointcut="within(com.tedu.cloudnote.controller..*)"/> <!-- 方法限定类型 -->
<aop:before method="logController"
pointcut="execution(* com.tedu.cloudnote.service.*.*(..))" /> <!-- bean名称限定类型-->
<aop:before method="logController"
pointcut="bean(userLoginController)"/>
</aop:aspect>
</aop:config> -->
 	<bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
<bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
<bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
<aop:config>
<aop:aspect id="time" ref="timeHandler">
<aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
<aop:before method="printTime" pointcut-ref="addAllMethod" />
<aop:after method="printTime" pointcut-ref="addAllMethod" />
</aop:aspect>
</aop:config>

AspectJ风格

xml配置文件

<?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:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"> <!-- 注解 AOP配置 -->
<context:component-scan
base-package="com.tedu.cloudnote.aspect"/>
<!-- 开启AOP注解标记的使用,例如@Aspect,@Before,@After -->
<aop:aspectj-autoproxy />
</beans>

添加的功能,aop类

@Component   // 扫描,等价于<bean>定义
@Aspect // 等价于<aop:aspect>定义
public class AspectJAdvice { // 等价于<aop:before>定义
// 在Controller方法执行前,先执行logController处理
@Before("within(com.tedu.cloudnote.controller..*)")
public void logController() { System.out.println("进入Controller处理请求");
} @Around("within(com.tedu.cloudnote.service..*)")
public Object test(ProceedingJoinPoint jp) throws Throwable {
long t1 = System.currentTimeMillis();
Object val = jp.proceed();// 目标业务方法
long t2 = System.currentTimeMillis();
long t = t2 - t1; // JoinPoint 对象可以获取目标业务方法的
// 详细信息: 方法签名, 调用参数等
Signature m = jp.getSignature();
// Signature: 签名, 这里是方法签名
System.out.println(m + "用时:" + t);
return val;
} // e就是目标组件方法抛出的异常对象
@AfterThrowing(throwing = "e", pointcut = "within(com.tedu.cloudnote.controller..*)")
public void execute(Exception e) {
try {
// 将异常信息写入文件中
FileWriter fw = new FileWriter("D:\\note_error.log", true);
PrintWriter pw = new PrintWriter(fw);
// 利用pw对象写信息
Date time = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStr = sdf.format(time);
pw.println("-----------------------------------------");
pw.println("*异常类型:*" + e);
pw.println("*发生时间:*" + timeStr);
pw.println("*异常详情: *");
e.printStackTrace(pw);
pw.close();
fw.close();
} catch (Exception ex) {
System.out.println("记录异常失败");
}
} }

注解配置的

@Pointcut

声明切入点

**@Pointcut(value="切入点表达式", argNames = "参数名列表") **

public void pointcutName(……) {}

value:指定切入点表达式(在哪切);

argNames:指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。

pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式。

@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
public void beforePointcut(String param) {} 定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。

@Before

前置通知

**@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名") **

value:指定切入点表达式或命名切入点;

argNames:与Schema方式配置中的同义。

@AfterReturnin

后置返回通知

**@AfterReturning(value="切入点表达式或命名切入点",

pointcut="切入点表达式或命名切入点",

argNames="参数列表参数名",

returning="返回值对应参数名") **

/实例
@AfterReturning(
value="execution(* cn.javass..*.sayBefore(..))",
pointcut="execution(* cn.javass..*.sayAfterReturning(..))",
argNames="retVal", returning="retVal")
public void afterReturningAdvice(Object retVal) {
System.out.println("===========after returning advice retVal:" + retVal);

@AfterThrowing

后置异常通知

**@AfterThrowing (

value="切入点表达式或命名切入点",

pointcut="切入点表达式或命名切入点",

argNames="参数列表参数名",

throwing="异常对应参数名")

**

@AfterThrowing(
value="execution(* cn.javass..*.sayAfterThrowing(..))",
argNames="exception", throwing="exception")
public void afterThrowingAdvice(Exception exception) {
System.out.println("===========after throwing advice exception:" + exception);
}

注:pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

@After

后置最终通知:

**@After (

value="切入点表达式或命名切入点",

argNames="参数列表参数名")

**

@Around

环绕通知

**@Around (

value="切入点表达式或命名切入点",

argNames="参数列表参数名") **

@Around(value="execution(* cn.javass..*.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;
}

java版云笔记(六)之AOP的更多相关文章

  1. java版云笔记(一)

    云笔记项目 这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址为:http://download.csdn.net/download/liveor_die/998584 ...

  2. java版云笔记(九)之动态sql

    SQL 首先,所谓SQL的动态和静态,是指SQL语句在何时被编译和执行,二者都是用在SQL嵌入式编程中的,这里所说的嵌入式是指将SQL语句嵌入在高级语言中,而不是针对于单片机的那种嵌入式编程. 静态S ...

  3. java版云笔记(七)之事务管理

    事务管理 事务:程序为了保证业务处理的完整性,执行的一条或多条SQL语句. 事务管理:对事务中的SQL语句进行提交或者回滚. 事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...

  4. java版云笔记(二)

    云笔记 基本的环境搭建好了,今天做些什么呢,第一是链接数据库(即搭建Spring-Batistas环境),第二是登录预注册. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下 ...

  5. java版云笔记(八)之关联映射

    Mybatis关联映射 通过数据库对象之间的关联关系,反映到到实体对象之间的引用. 加载多个表中的关联数据,封装到我们的实体对象中. 当业务对数据库进行关联查询. 关联 <association ...

  6. java版云笔记(五)

    下来是创建笔记本,创建笔记,这个没什么难点和前面是一样的. 创建笔记本 首先点击"+"弹出添加笔记的对话框,然后点击确定按钮创建笔记本. //点击"+"弹出添加 ...

  7. java版云笔记(四)

    页面的笔记本加载完成了,接下来就是点击笔记本显示将笔记显示,同时把笔记在右边的编辑器中,同时把编辑后的笔记更新. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址 ...

  8. java版云笔记(三)

    登录与注册写好了下来就是主页,今天写的是主页加载时笔记本列表的显示,ajax是固定的就不重点说了.主要说一下jQuery.data() 函数和jQuery.on() 函数. 注:这个项目的sql文件, ...

  9. 第六篇 :微信公众平台开发实战Java版之如何自定义微信公众号菜单

    我们来了解一下 自定义菜单创建接口: http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_to ...

随机推荐

  1. 【转】NHibernate 各种数据库配置

    转载自:http://terrylee.cnblogs.com/archive/2006/04/05/367381.html 自己只用了Oracle 可用! 三.常见的配置示例 Castle网站为我们 ...

  2. 【BZOJ2141】排队(CDQ分治)

    [BZOJ2141]排队(CDQ分治) 题面 题面以及树套树做法见这里 题解 大部分树套树/主席树这类题目都可以用整体二分/CDQ分治来做. 这题考虑一下,在不考虑修改的情况下 贡献是如何产生的? 我 ...

  3. Red Hat下升级python的问题

    分为两部分: 一,升级Python 安装的包的渠道(传送门),安装过程的渠道(传送门). 二.涉及的问题 1.yum不能使用 解决办法(传送门),其中的部分就行.

  4. springMVC参数绑定与数据回显

    简单例子:修改商品信息的jsp页面: 参数绑定过程: 1.2.1  默认支持的参数类型 处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值. 1.1.1     HttpServletReq ...

  5. python学习笔记(四) 思考和准备

    一.zip的坑 zip()函数接收多个可迭代数列,将数列中的元素重新组合,在3.0中返回迭代器指向 数列首地址,在3.0以下版本返回List类型的列表数列.我用的是3.5版本python, 所以zip ...

  6. 手脱EZIP v1.0

    一.单步 1.载入PEID查壳 EZIP v1.0 2.载入OD,一上来就是一个大跳转,F8单步一直走 0040D0BE > $ /E9 jmp Notepad.004102DC ; //入口点 ...

  7. 配置:heartbeat+nginx+mysqld+drbd高可用笔记(OK)

    参考资料:http://www.centoscn.com/CentosServer/cluster/2015/0605/5604.html   背景需求: 使用heartbeat来做HA高可用,并且把 ...

  8. Hibernate学习(3)- *.hbm.xml详解

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBL ...

  9. 往android主项目中添加辅助项目

    一个较大的工程往往需要多个项目组成,便于更好的并行开发和管理,但最后还是要合到一起来发布.那如何往主项目里添加其他辅助项目呢? 通常的做法是将辅助项目打包成jar包,像库一样导入到主项目,但是如果我们 ...

  10. JS数字计算精度问题解决

    add(a, b) {//相加 var c, d, e; try { c = a.toString().split(".")[1].length; } catch (f) { c ...