Aop的基本介绍
基本概念
- 通知
就是你想要的功能,也就是我们常说的安全、事物、日志等。先定义好这些,然后再想用的地方用一下。包含Aspect的一段处理代码
注意:其实这些功能(通知)并不是我们业务逻辑所必须的,只是为了安全,输出信息,或者其他的原因,总之是为了方便我们对项目维护而增加的操作,一般我们会把这些功能封装成相关的方法,但是我们又不想这些功能直接入侵我们的正常业务代码,因为这样会增加关注度并且污染我们的业务逻辑,所以我们就用切面的思想来很好解决这个问题
- 连接点
就是spring允许你加 通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring一般只支持方法连接点,除非引入其他的aop框架才可以实现更细粒度的连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点
- 切入点
在上面说的连接点的基础上,来定义切入点。例如:你的一个类里,有15个方法,那就有至少十几个连接点了对吧,但是你并不想在所有方法附近都使用通知(使用叫织入,下面再说),你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法
注意:切入点定义的一般是你的业务中的某些方法(也有可能是某些特殊地方,在“特例”下有个例子切点切的就是方法,而是自定义的注解),就是供切面实际切入的地方,也就是需要执行通知的地方
- 切面
用来切插业务方法的类。
切面是通知和切入点的结合。现在发现了吧,没连接点什么事,链接点就是为了让你好理解切点搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的befor,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义
- 目标
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面,而自己专注于业务本身的逻辑。
- 代理
怎么实现整套AOP机制的,都是通过代理,这个一会儿给细说
- 织入(weaving)
把切面应用到目标对象来创建新的代理对象的过程。有三种方式,spring采用的是运行时,为什么是运行时,在上一文《Spring AOP开发漫谈之初探AOP及AspectJ的用法》中第二个标提到
- 目标对象
项目原始的Java组件。
- AOP代理
由AOP框架生成java对象。
- AOP代理方法
代理方法= advice + 目标对象的方法。
xml方式配置详解
- aop所需jar包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
- 在使用xml方式的Aop时,首先要保证xml头部引入了aop包和spring的基础包,如下:
<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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
- 在spring-context.xml(也就是spring的主配置文件)中加入<aop:aspectj-autoproxy/>
- aop具体代码
<!-- 定义普通的Bean实例 -->
<
bean
id
=
"adviceTest"
class
=
"com.abc.advice.AdviceTest"
/>
<
aop:config
>
<!-- 将容器中的adviceTest转换成切面Bean -->
<!-- 注意这里可以使用order属性为Aspect指定优先级 -->
<
aop:aspect
id
=
"firstAspect"
ref
=
"adviceTest"
order
=
"2"
>
<!-- @Before切点 -->
<
aop:before
pointcut
=
"execution(* com.abc.service.*.*(..))"
method
=
"permissionCheck" arg-names="name,age"
/>
<!-- @After切点 -->
<
aop:after
pointcut
=
"execution(* com.abc.service.*.*(..))"
method
=
"releaseResource"
/>
<!-- @AfterReturning切点 -->
<
aop:after-returning
pointcut
=
"execution(* com.abc.service.*.*(..))"
method
=
"log" returning="discussion" arg-names="discussion"
/>
<!-- @AfterThrowing切点 -->
<
aop:after-throwing
pointcut
=
"execution(* com.abc.service.*.*(..))"
method
=
"handleException"
/>
<!-- @Around切点(多个切点提示符使用and、or或者not连接) -->
<
aop:around
pointcut
=
"execution(* com.abc.service.*.*(..)) and args(name,time,..)"
method
=
"process"
/>
<!-切入点第二种写法开始->
<!-单参数传参->
<aop:pointcut id="thinking" expression="execution(* com.bird.springidol.Thinker.thinkOfSomething(String)) and args(thoughts)"/>
<aop:pointcut id="log4add" expression="execution(* com.tfedu.discuss.web.TeacherDiscussionController.delete(com.tfedu.discuss.abutment.TestAddLog)) and args(testAddLog)" />
<aop:after method="addLog" pointcut-ref="log4add" arg-names="testAddLog"/>
<!-切入点第二种写法结束->
<!-切点为注解时,也就是将切点切到注解上 开始->
</
aop:aspect
>
</
aop:config
>
- pointcut-ref:当pointcut单独写时,在通知标签里,要是用pointcut-ref属性来指向响应的切点Id
- method:一般对应的是切面中的通知方法
- arg-names:定义的是通知方法中的参数。一般通知方法中需要使用切点方法的参数时,这个属性最好加上(当然有时不写也可以传参),并且和expression表达式中的args()的小括号中的名称保持一直
- order:
Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟spring的事务aop执行的先后顺序问题,比如说动态切换数据源的问题,如果事务在前,数据源切换在后,会导致数据源切换失效,所以就用到了Order(排序)这个关键字.我们可以通过在@AspectJ的方法中实现org.springframework.core.Ordered 这个接口来定义order的顺序,order 的值越小,说明越先被执行
特例(某注解为切点时)
一般我们认为切点的位置都是某个业务方法之前,之后或者前后都有,但是有些情况下我们也可以将切点切到某个方法的注解上,在解决某些问题时很方便,下面举例说明此种用法:
配置文件中内容
<bean id="abutmentAspect" class="com.tfedu.discuss.abutment.aop.LogAspect"></bean>
<aop:config>
<aop:aspect id="" ref="abutmentAspect">
<aop:pointcut id="addLog" expression="@annotation(com.tfedu.discuss.annotation.BehaviorLog)" />
<aop:after method="behaviorLog4Review" pointcut-ref="addLog"/>
</aop:aspect>
</aop:config>
注解类
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Documented
public @interface BehaviorLog {
OperTypeEnum value();//这里面定义的方法要在注解上用到,这里的方法名就是注解上的等号左边的值
String fiterName();
}
注意:里面的方法可以根据具体需要来定义
注解的使用
在业务方法上加上:@BehaviorLog(value = OperTypeEnum.REVIEW, fiterName = "historyDraftId")
通知方法代码
public void behaviorLog4Review(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
String fiterName = method.getAnnotation(BehaviorLog.class).fiterName();//这里获取的是注解中定义的各种方法的值,例如这里获取的注解上的fiterName等号后面的的值 Object[] args = joinPoint.getArgs();//这里获取的是方法里的参数不是注解上的值,这个切记
Long historyDraftId = getParam4Common(args, fiterName);
HistoryDraftEntity historyDraftEntity = historyDraftBaseService.get(historyDraftId);
if (Util.isEmpty(historyDraftEntity)) {
ExceptionUtil.bEx("批阅中添加行为日志记录是,历史稿对象不能为空", historyDraftEntity);
}
addLog(historyDraftId, LogTypeEnum.WRITING.key(), historyDraftEntity.getTitle(), fetchUser.getCurrentUserId(),
OperTypeEnum.REVIEW.key());
} private Long getParam4Common(Object[] args, String fiterName) {
Optional<Object> obj = Arrays.stream(args).findFirst();
if (!obj.isPresent()) {
return PARAM_ID;
}
return ConvertUtil.obj2long(BeanUtil.get((obj.get()), fiterName));
}
Aop的基本介绍的更多相关文章
- Spring入门篇——第6章 Spring AOP的API介绍
第6章 Spring AOP的API介绍 主要介绍Spring AOP中常用的API. 6-1 Spring AOP API的Pointcut.advice概念及应用 映射方法是sa开头的所有方法 如 ...
- AOP的成员介绍
AOP(Aspect Oriented Programming)面向切面编程,AOP的作用不过多介绍,本文是主要是介绍AOP的成员,是我在复习的时候记录的一些笔记,方便以后查阅方便一些. JointP ...
- spring aop做什么介绍
1.AOP(Aspect Orient Programming),称为面向切面编程,它作为面向对象(OOP)的一种补充,用于处理系统中分布于各个模板的横切关注点,比如事务管理.日志.缓存等.AOP实现 ...
- spring AOP(切面) 表达式介绍
在 spring AOP(切面) 例子基础上对表达式进行介绍 1.添加接口删除方法 2.接口实现类 UserDaoServer 添加实现接口删除方法 3.测试类调用delUser方法 4. 输出结果截 ...
- [刘阳Java]_Spring AOP注解详细介绍_第8讲
这节内容非常关键,我们会比较详细地介绍Spring AOP注解的使用 1. 要使用Spring AOP注解,必须满足如下的事项 导入Aspectj的jar.Spring3.0-AOP.jar.aopa ...
- Spring基础只是—AOP的概念介绍
Spring容器包含两个重要的特性:面向切面编程(AOP)和控制反转(IOC).面向切面编程是面向对象(OOP)的一种补充,在面向对象编程的过程中编程针对的目标是一个个对象,而面向切面编程中编程针对的 ...
- Spring Aop重要概念介绍及应用实例结合分析
转自:http://bbs.csdn.net/topics/390811099 此前对于AOP的使用仅限于声明式事务,除此之外在实际开发中也没有遇到过与之相关的问题.最近项目中遇到了以下几点需求,仔细 ...
- spring---aop(7)---Spring AOP中expose-proxy介绍
写在前面 expose-proxy.为是否暴露当前代理对象为ThreadLocal模式. SpringAOP对于最外层的函数只拦截public方法,不拦截protected和private方法(后续讲 ...
- spring---aop(6)---Spring AOP中ProxyFactoryBean介绍
写在前面 这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP. 简单例子 Spring自己的AOP实现在于Pr ...
随机推荐
- servlet中web.xml配置详解
Web.xml常用元素 <web-app> 所有部署描述符文件的顶层(根)元素 <display-name></display-name>定义了WEB应用的名字 & ...
- 【GMT43智能液晶模块】例程六:WWDG看门狗实验——复位ARM
实验原理: STM32内部包含窗口看门狗,通过看门狗可以监控程序运行,程序运行 错误时,未在规定时间喂狗,自动复位ARM.本实验通过UI界面中按钮按下 停止喂狗,制造程序运行错误,从而产生复位. 示例 ...
- 编译错误“The run destination My Mac is not valid for Running the scheme '***',解决办法
[转载] http://blog.csdn.net/duanyipeng/article/details/8007684 编译错误"The run destination My Ma ...
- django template if return false
如果if的参数不存在于context中就会返回false 参考:http://stackoverflow.com/questions/11107028/django-template-if-true- ...
- Web - JSONP和同源策略漫谈
0x00 前言 关于JSONP网上有很多文章了,我也是在拜读了别人的文章的基础上来写写自己的看法,这样可以加深自己印象,巩固一下学习效果.我们需要做的就是站在巨人的肩膀上眺望远方. 0x01 起 在W ...
- VS2012+openCV 2.4.8进行编译:VS2012 64位 使用OPENCV应用程序不能正常启动 (0xc000007b)怎么处理?
[OpenCV入门教程之一] 安装OpenCV:OpenCV 2.4.8 +VS 开发环境配置 http://blog.csdn.net/poem_qianmo/article/details/198 ...
- java-信息安全(六)-基于RSA理解数字签名示例
概述 java-信息安全(四)-数据签名.数字证书 java-信息安全(五)-非对称加密算法RSA RSA工具类 使用java-信息安全(五)-非对称加密算法RSA项目中RSACoder 数字签名理解 ...
- printf打印输出null问题的跟踪
最近在工作中,遇到一处 printf输出有null的情况,在此记录一下,问题分析的过程. 测试代码很简单,本机为64位操作系统: #include <stdio.h> #include & ...
- [hive] hive 安装、配置
一.hive安装 1.官网下载 1.2.2版本 http://apache.fayea.com/hive/hive-1.2.2/ 2. 解压,此处目录为 /opt/hadoop/hive-1.2.2 ...
- mysql按月查询
SELECT DATE_FORMAT(GenerateTime, '%m') as month, SUM(GenerateCount) AS count FROM identitycodetask ' ...