java版云笔记(六)之AOP
今天主要是利用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的更多相关文章
- java版云笔记(一)
云笔记项目 这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址为:http://download.csdn.net/download/liveor_die/998584 ...
- java版云笔记(九)之动态sql
SQL 首先,所谓SQL的动态和静态,是指SQL语句在何时被编译和执行,二者都是用在SQL嵌入式编程中的,这里所说的嵌入式是指将SQL语句嵌入在高级语言中,而不是针对于单片机的那种嵌入式编程. 静态S ...
- java版云笔记(七)之事务管理
事务管理 事务:程序为了保证业务处理的完整性,执行的一条或多条SQL语句. 事务管理:对事务中的SQL语句进行提交或者回滚. 事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...
- java版云笔记(二)
云笔记 基本的环境搭建好了,今天做些什么呢,第一是链接数据库(即搭建Spring-Batistas环境),第二是登录预注册. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下 ...
- java版云笔记(八)之关联映射
Mybatis关联映射 通过数据库对象之间的关联关系,反映到到实体对象之间的引用. 加载多个表中的关联数据,封装到我们的实体对象中. 当业务对数据库进行关联查询. 关联 <association ...
- java版云笔记(五)
下来是创建笔记本,创建笔记,这个没什么难点和前面是一样的. 创建笔记本 首先点击"+"弹出添加笔记的对话框,然后点击确定按钮创建笔记本. //点击"+"弹出添加 ...
- java版云笔记(四)
页面的笔记本加载完成了,接下来就是点击笔记本显示将笔记显示,同时把笔记在右边的编辑器中,同时把编辑后的笔记更新. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址 ...
- java版云笔记(三)
登录与注册写好了下来就是主页,今天写的是主页加载时笔记本列表的显示,ajax是固定的就不重点说了.主要说一下jQuery.data() 函数和jQuery.on() 函数. 注:这个项目的sql文件, ...
- 第六篇 :微信公众平台开发实战Java版之如何自定义微信公众号菜单
我们来了解一下 自定义菜单创建接口: http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_to ...
随机推荐
- CF878C Tournament set 图论
题面 题面 题解 如果2个人可以互相战胜,那么我们连一条无向边,于是最后会剩下t个联通块,其中每对联通块之间都有严格的大小关系(a.max < b.min),因此我们每插入一个点就相当于合并一段 ...
- Mybatis笔记四:nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'id' in 'class java.lang.String'
错误异常:nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for pr ...
- 【POJ2891】Strange Way to Express Integers(拓展CRT)
[POJ2891]Strange Way to Express Integers(拓展CRT) 题面 Vjudge 板子题. 题解 拓展\(CRT\)模板题. #include<iostream ...
- tomcat7.x远程命令执行(CVE-2017-12615)漏洞漏洞复现
tomcat7.x远程命令执行(CVE-2017-12615)漏洞漏洞复现 一.漏洞前言 2017年9月19日,Apache Tomcat官方确认并修复了两个高危漏洞,漏洞CVE编号:CVE-2017 ...
- 第一个python教程(1)
使用文本编辑器 在Python的交互式命令行写程序,好处是一下就能得到结果,坏处是没法保存,下次还想运行的时候,还得再敲一遍. 所以,实际开发的时候,我们总是使用一个文本编辑器来写代码,写完了,保存为 ...
- Spark集群基础概念 与 spark架构原理
一.Spark集群基础概念 将DAG划分为多个stage阶段,遵循以下原则: 1.将尽可能多的窄依赖关系的RDD划为同一个stage阶段. 2.当遇到shuffle操作,就意味着上一个stage阶段结 ...
- 网络编程----粘包以及粘包问题的解决、FTP上传
一.粘包现象 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意: res=subprocess.Popen(cmd.decode('u ...
- static_cast 和 dynamic_cast
1.static_cast static_cast < type-id > ( expression ) 该运算符把expression转换为type-id类型,但没有运行时类型检查来保证 ...
- 《剑指offer》— JavaScript(6)旋转数组的最小数字
旋转数组的最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2, ...
- array_diff、array_diff_key、array_diff_ukey、array_diff_assoc、array_diff_uassoc 的用法
<?php // array_diff* 系列的函数都返回关联数组// array_diff* 系列函数返回数组的差集(返回在第一个参数中, 但不在其他参数中的元素) $array1 = [ ' ...