AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

一 AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

二 Spring AOP

Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

三 基于注解的AOP配置方式

1.启用@AsjectJ支持

在applicationContext.xml中配置下面一句:

<aop:aspectj-autoproxy />

2.通知类型介绍

(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可

(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值

(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名

来访问目标方法中所抛出的异常对象

(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式

(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

3.例子:

(1)Operator.java --> 切面类

@Component
@Aspect
public class Operator { @Pointcut("execution(* com.aijava.springcode.service..*.*(..))")
public void pointCut(){} @Before("pointCut()")
public void doBefore(JoinPoint joinPoint){
System.out.println("AOP Before Advice...");
} @After("pointCut()")
public void doAfter(JoinPoint joinPoint){
System.out.println("AOP After Advice...");
} @AfterReturning(pointcut="pointCut()",returning="returnVal")
public void afterReturn(JoinPoint joinPoint,Object returnVal){
System.out.println("AOP AfterReturning Advice:" + returnVal);
} @AfterThrowing(pointcut="pointCut()",throwing="error")
public void afterThrowing(JoinPoint joinPoint,Throwable error){
System.out.println("AOP AfterThrowing Advice..." + error);
System.out.println("AfterThrowing...");
} @Around("pointCut()")
public void around(ProceedingJoinPoint pjp){
System.out.println("AOP Aronud before...");
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("AOP Aronud after...");
} }

(2)UserService.java --> 定义一些目标方法

@Service
public class UserService { public void add(){
System.out.println("UserService add()");
} public boolean delete(){
System.out.println("UserService delete()");
return true;
} public void edit(){
System.out.println("UserService edit()");
int i = 5/0;
} }

(3).applicationContext.xml

<context:component-scan base-package="com.aijava.springcode"/>

<aop:aspectj-autoproxy />

(4).Test.java

public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.add();
}
}

上面是一个比较简单的测试,基本涵盖了各种增强定义。注意:做环绕通知的时候,调用ProceedingJoinPoint的proceed()方法才会执行目标方法。

4.通知执行的优先级

进入目标方法时,先织入Around,再织入Before,退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。

注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用!同时使用也没啥意义。

5.切入点的定义和表达式

切入点表达式的定义算是整个AOP中的核心,有一套自己的规范

Spring AOP支持的切入点指示符:

(1)execution:用来匹配执行方法的连接点

A:@Pointcut("execution(* com.aijava.springcode.service..*.*(..))")

第一个*表示匹配任意的方法返回值,..(两个点)表示零个或多个,上面的第一个..表示service包及其子包,第二个*表示所有类,第三个*表示所有方法,第二个..表示

方法的任意参数个数

B:@Pointcut("within(com.aijava.springcode.service.*)")

within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点

C:@Pointcut("this(com.aijava.springcode.service.UserService)")

this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService

D:@Pointcut("bean(userService)")

bean也是非常常用的,bean可以指定IOC容器中的bean的名称

6.基于XML形式的配置方式

开发中如果选用XML配置方式,通常就是POJO+XML来开发AOP,大同小异,无非就是在XML文件中写切入点表达式和通知类型

例子:

(1)Log.java

public class Log {

    private Integer id;

    //操作名称,方法名
private String operName; //操作人
private String operator; //操作参数
private String operParams; //操作结果 成功/失败
private String operResult; //结果消息
private String resultMsg; //操作时间
private Date operTime = new Date(); setter,getter }

(2).Logger.java

/**
* 日志记录器 (AOP日志通知)
*/
public class Logger { @Resource
private LogService logService; public Object record(ProceedingJoinPoint pjp){ Log log = new Log();
try {
log.setOperator("admin");
String mname = pjp.getSignature().getName();
log.setOperName(mname); //方法参数,本例中是User user
Object[] args = pjp.getArgs();
log.setOperParams(Arrays.toString(args)); //执行目标方法,返回的是目标方法的返回值,本例中 void
Object obj = pjp.proceed();
if(obj != null){
log.setResultMsg(obj.toString());
}else{
log.setResultMsg(null);
} log.setOperResult("success");
log.setOperTime(new Date()); return obj;
} catch (Throwable e) {
log.setOperResult("failure");
log.setResultMsg(e.getMessage());
} finally{
logService.saveLog(log);
}
return null;
}
}

(3).applicationContext.xml

<aop:config>
<aop:aspect id="loggerAspect" ref="logger">
<aop:around method="record" pointcut="(execution(* com.aijava.distributed.ssh.service..*.add*(..))
or execution(* com.aijava.distributed.ssh.service..*.update*(..))
or execution(* com.aijava.distributed.ssh.service..*.delete*(..)))
and !bean(logService)"/>
</aop:aspect>
</aop:config>

注意切入点表达式,!bean(logService) 做日志通知的时候,不要给日志本身做日志,否则会造成无限循环!

有关更详细的Spring AOP知识,可以查看Spring官方文档第9章Aspect Oriented Programming with Spring

7.JDK动态代理介绍

例子:

(1)UserService.java

public interface UserService {

    public void add();
}

(2)UserServiceImpl.java

public class UserServiceImpl implements UserService{

    public void add() {
System.out.println("User add()...");
} }

(3)ProxyUtils.java

public class ProxyUtils implements InvocationHandler{

    private Object target;

    public ProxyUtils(Object target){
this.target = target;
} public Object getTarget() {
return target;
} public void setTarget(Object target) {
this.target = target;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do sth before...");
method.invoke(target, args);
System.out.println("do sth after...");
return null;
} }

(4)Test.java

public class Test {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ProxyUtils proxyUtils = new ProxyUtils(userService);
UserService proxyObject = (UserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),UserServiceImpl.class.getInterfaces(), proxyUtils);
proxyObject.add();
}
}

JDK动态代理核心还是一个InvocationHandler,记住这个就行了。

Spring AOP详细介绍的更多相关文章

  1. Spring AOP 详细介绍

    一.理解 “面向切面编程” 面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Prog ...

  2. spring AOP 之一:spring AOP功能介绍

    一.AOP简介 AOP:是一种面向切面的编程范式,是一种编程思想,旨在通过分离横切关注点,提高模块化,可以跨越对象关注点.Aop的典型应用即spring的事务机制,日志记录.利用AOP可以对业务逻辑的 ...

  3. spring——aop详细总结1

    AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补 ...

  4. 理解Spring AOP的实现方式与思想

    Spring AOP简介 如果说IOC是Spring的核心,那么面向切面编程就是Spring最核心的功能之一了,在数据库事务中,面向切面编程被广泛应用. AOP能够将那些与业务无关,却为业务模块所共同 ...

  5. Spring相框:AOP详细说明

    AOP中国的名字叫做面向方面编程.这个名字是很形象.因为你真的可以把像面包切系统.并直接增加面包的修改.科而异,对整个系统,小到一定的方法. AOP它有什么用?有关示例,各组分可以含有安全.事务.,A ...

  6. spring aop介绍和示例

    参考:<Spring in Action> 一.AOP介绍 AOP是Aspect Oriented Programming的缩写,意思是面向切面编程. 应用中有一些功能使用非常普遍,比如事 ...

  7. Spring AOP介绍与使用

    Spring AOP介绍与使用 AOP:Aspect Oriented Programming 面向切面编程 OOP:Object Oriented Programming 面向对象编程 ​ 面向切面 ...

  8. [刘阳Java]_Spring AOP注解详细介绍_第8讲

    这节内容非常关键,我们会比较详细地介绍Spring AOP注解的使用 1. 要使用Spring AOP注解,必须满足如下的事项 导入Aspectj的jar.Spring3.0-AOP.jar.aopa ...

  9. Spring AOP介绍

    1.介绍 AOP(面向切面编程)对OOP(面向对象编程)是一种补充,它提供了另一种程序结构的思路.OOP的模块单元是class,而AOP的模块单元是aspect.Spring中一个关键的组件是AOP框 ...

随机推荐

  1. python 实现网页 自动登录

    完整代码: 1 from apscheduler.schedulers.blocking import BlockingScheduler 2 from selenium import webdriv ...

  2. PE 添加系统管理员账号(域控可加)转

    使用U盘制作一个PE系统,这里推荐老毛桃或者大白菜:开机进入Bios,选择U盘启动:进入U盘启动画面后,选择一个PE系统:进入PE系统后,我们去本机系统盘,将 C:/Windows/System32/ ...

  3. 用PHP打造一个高性能好用的网站

    用PHP打造一个高性能好用的网站 1. 说到高可用的话要提一下redis,用过的都知道redis是一个具备数据库特征的nosql,正好弥补了PHP的瓶颈,个人认为PHP的 瓶颈在于数据库,像Apach ...

  4. Fiddler抓包学习

    今天看到一个抓包笔记, 因为是老早抓包的需求, 后期不用就忘了, 换电脑桌面软件图标都没了, 点开看了一下一脸懵逼... 这是啥...  以后有需要在看一遍吧! Fiddler抓包使用教程-扫盲篇 h ...

  5. 指数加权移动平均法(EWMA)

    ** 本文内容来自于吴恩达深度学习公开课 1.概述 加权移动平均法,是对观察值分别给予不同的权数,按不同权数求得移动平均值,并以最后的移动平均值为基础,确定预测值的方法.采用加权移动平均法,是因为观察 ...

  6. 【转】编写微信聊天机器人4《聊天精灵WeChatGenius》:实时获取到微信聊天消息,hook数据库插入操作。

    接上篇,使用Xposed来hook微信,找到微信进程:https://blog.csdn.net/weixin_42127613/article/details/81839537 既然已经找到了微信进 ...

  7. C# WebApi 获取客户端ip地址

    转自:http://www.cnblogs.com/weixing/p/5674078.html References required: HttpContextWrapper - System.We ...

  8. WiFi-ESP8266入门http(2-2)文件系统-复杂结构的网页 + 文本框交互WIFI信息

    网友教程:https://blog.csdn.net/solar_Lan/article/details/74231360 通过网友教程,我们搭建了文件系统.在此基础上,我们增加WIFI交互. 现有功 ...

  9. RabbitMQ的六种工作模式

    一.基于erlang语言: 是一种支持高并发的语言 RabbitMQ的六种工作模式: 1.1 simple简单模式 消息产生着§将消息放入队列 消息的消费者(consumer) 监听(while) 消 ...

  10. 深度学习框架PyTorch一书的学习-第一/二章

    参考https://github.com/chenyuntc/pytorch-book/tree/v1.0 希望大家直接到上面的网址去查看代码,下面是本人的笔记 pytorch的设计遵循tensor- ...