AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

使用"横切"技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

基于Spring的AOP简单实现

1、通过配置文件实现AOP

首先需要额外上网下载两个jar包:

  ① aspectjrt.jar
  ② aspectjweaver.jar

先定义一个接口IHelloWorld:

 public interface IHelloWorld {
void printHelloWorld(String name);
}

定义一个实现类HelloWorld

 public class HelloWorld implements IHelloWorld {

     @Override
public void printHelloWorld(String name) {
System.out.println("Print HelloWorld :" + name);
}
}

实现了两个切面(一个日志切面和一个时间切面)

 public class LogAspect {
public void beforeLog(JoinPoint joinPoint){
System.out.println("log before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
public void afterLog(JoinPoint joinPoint){
System.out.println("log after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
}
 public class TimeAspect {
public void beforeTime(JoinPoint joinPoint){
System.out.println("time before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
public void afterTime(JoinPoint joinPoint){
System.out.println("time after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
}

定义一个配置文件

 <?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 核心业务Bean -->
<bean id="helloworld" class="com.hzg.HelloWorld"></bean> <!-- 切面Bean(日志切面) -->
<bean id="logAspect" class="com.hzg.LogAspect"></bean> <!-- 切面Bean(时间切面) -->
<bean id="timeAspect" class="com.hzg.TimeAspect"></bean> <!-- AOP配置 -->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut id="pointcut" expression="execution(* com.hzg.IHelloWorld.*(..))"></aop:pointcut>
<!-- 配置切面(日志切面)切面的优先级需要通过order定义 -->
<aop:aspect id="log" ref="logAspect" order="1">
<!-- 配置通知(前置通知、后置通知、返回通知、异常通知、环绕通知) -->
<aop:before method="beforeLog" pointcut-ref="pointcut"></aop:before>
<aop:after method="afterLog" pointcut-ref="pointcut"></aop:after>
</aop:aspect>
<!-- 配置切面(时间切面)切面的优先级需要通过order定义 -->
<aop:aspect id="time" ref="timeAspect" order="2">
<!-- 配置通知(前置通知、后置通知、后置返回通知、异常通知、环绕通知) -->
<aop:before method="beforeTime" pointcut-ref="pointcut"></aop:before>
<aop:after method="afterTime" pointcut-ref="pointcut"></aop:after>
</aop:aspect>
</aop:config> </beans>

定义Main主方法

 public static void main(String[] args) {
//由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext
ApplicationContext ctx = new ClassPathXmlApplicationContext("configaop.xml");
IHelloWorld helloworld = (IHelloWorld) ctx.getBean("helloworld");
helloworld.printHelloWorld("gangge");
}

输出结果:

log before method printHelloWorld参数 :[gangge]
time before method printHelloWorld参数 :[gangge]
Print HelloWorld :gangge
time after method printHelloWorld参数 :[gangge]
log after method printHelloWorld参数 :[gangge]

2、通过注解实现AOP

实现配置文件方式同样的功能

先定义一个接口文件(没区别)

 public interface IHelloWorld {
void printHelloWorld(String name);
}

定义实现类(区别:加了一个注解@Component)

 @Component
public class HelloWorld implements IHelloWorld { @Override
public void printHelloWorld(String name) {
System.out.println("Print HelloWorld :" + name);
}
}

定义两个切面(一个日志切面和一个时间切面 区别:增加了@Component、@Aspect和@Order注解)

 @Component
@Aspect
@Order(1)
public class LogAspect {
public void beforeLog(JoinPoint joinPoint){
System.out.println("log before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
public void afterLog(JoinPoint joinPoint){
System.out.println("log after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
}
 @Component
@Aspect
@Order(2)
public class TimeAspect {
@Before("execution(* com.hzg.HelloWorld.*(..))")
public void beforeTime(JoinPoint joinPoint){
System.out.println("time before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
@After("execution(* com.hzg.HelloWorld.*(..))")
public void afterTime(JoinPoint joinPoint){
System.out.println("time after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
}
}

定义配置文件(区别:Spring自动扫描包和aop自动代理)

 <?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.hzg"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>

定义Main主方法(无区别)

 public static void main(String[] args) {
//由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext
ApplicationContext ctx = new ClassPathXmlApplicationContext("configaop.xml");
IHelloWorld helloworld = (IHelloWorld) ctx.getBean("helloworld");
helloworld.printHelloWorld("gangge");
}

输出结果和配置文件一样

五种通知

1、前置通知

  上面已经有了,不再说明

2、后置通知

  上面已经有了,不再说明

3、返回通知

 /**
* 返回通知: 方法正常执行完后调用,如果有异常,则不调用
* 可以访问到方法的返回值
* @param joinPoint
* @param result 方法的返回值
*/
@AfterReturning(value="execution(* com.hzg.*(..))",returning="result")
public void afterReturning(JoinPoint joinPoint,Object result){
//方法名
String methodName = joinPoint.getSignature().getName();
System.out.println("method "+methodName+" end:"+result);
}

4、异常通知

 /**
* 异常通知: 当方法出现异常时
* 可以指定出现哪些异常时才执行: 如何指定?通过入参指定,如:
* 如果入参为NullPointException ex,那么只有在发生空指针异常时才执行
* @param joinPoint
* @param ex
*/
@AfterThrowing(value="execution(* com.hzg.*(..))",throwing="ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
//方法名
String methodName = joinPoint.getSignature().getName();
System.out.println("method "+methodName+" occurs:"+ex);
}

5、环绕通知

  环绕通知类似于动态代理的全过程,可以使用环绕通知实现前置通知,后置通知,返回通知,异常通知的功能,十分强大,但并不常用

 /**
* 环绕通知需要携带ProceedingJoinPoint类型的参数
* 环绕通知类似于动态代理的全过程: ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法
* 且环绕通知必须有返回值,返回值即为目标方法的返回值
* @param pjd
*/
@Around("execution(* com.hzg.*(..))")
public Object around(ProceedingJoinPoint pjd){
Object result = null;
String methodName = pjd.getSignature().getName(); try {
//前置通知
System.out.println("method:"+methodName+" begins with "+Arrays.asList(pjd.getArgs()));
//执行目标方法
result = pjd.proceed();
//返回通知
System.out.println("method:"+methodName+" end with "+result);
} catch (Throwable e) {
// 异常通知
System.out.println("method:"+methodName+" occurs exception "+e);
}
//后置通知
System.out.println("method ends");
return result;
}

-------------------------------------------------------------------------------------------------------------------------

跟着刚哥学习Spring框架系列:

跟着刚哥学习Spring框架--创建HelloWorld项目(一)

跟着刚哥学习Spring框架--Spring容器(二)

跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

跟着刚哥学习Spring框架--AOP(五)

跟着刚哥学习Spring框架--JDBC(六)

跟着刚哥学习Spring框架--事务配置(七)

跟着刚哥学习Spring框架--AOP(五)的更多相关文章

  1. 跟着刚哥学习Spring框架--创建HelloWorld项目(一)

    1.Spring框架简介 Spring是一个开源框架,Spring是在2003年兴起的一个轻量级的开源框架,由Rod johnson创建.主要对JavaBean的生命周期进行管理的轻量级框架,Spri ...

  2. 跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

    组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: 1.@Component:基本注解,识别一个受Spring管理的组件 2.@Resposit ...

  3. 跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

    Spring配置Bean有两种形式(XML和注解) 今天我们学习通过XML方式配置Bean 1. Bean的配置方式 通过全类名(反射)的方式   √ id:标识容器中的bean.id唯一. √ cl ...

  4. 跟着刚哥学习Spring框架--Spring容器(二)

    Spring容器 启动Spring容器(实例化容器) -- IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化(加载启动),这样才可以从容器中获取Bean的实例并使用.  Bean是S ...

  5. 跟着刚哥学习Spring框架--事务配置(七)

    事务 事务用来保证数据的完整性和一致性. 事务应该具有4个属性:原子性.一致性.隔离性.持久性.这四个属性通常称为ACID特性.1.原子性(atomicity).一个事务是一个不可分割的工作单位,事务 ...

  6. 跟着刚哥学习Spring框架--JDBC(六)

    Spring的JDBC框架 Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要提供JDBC模板方式.关系数据库对象化方式.SimpleJdbc方式.事务管理来简 ...

  7. 深入浅出学习Spring框架(四):IoC和AOP的应用——事务配置

    在前文 深入浅出学习Spring框架(一):通过Demo阐述IoC和DI的优势所在. 深入浅出学习Spring框架(三):AOP 详解 分别介绍了Spring的核心功能——IoC和AOP,光讲知识远远 ...

  8. 23种设计模式之自定义Spring框架(五)

    7,自定义Spring框架 7.1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao ...

  9. spring框架 AOP核心详解

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

随机推荐

  1. 前端之css操作2

    一 伪类选择器 伪类选择器就是在查找的后面加上冒号和状态 hover:悬浮到上面就会变化一种状态 link:没有接触的状态 active:点击是触发的状态 visited:点击后的状态 <!DO ...

  2. 2018.12.17 bzoj1406 : [AHOI2007]密码箱(简单数论)

    传送门 简单数论暴力题. 题目简述:要求求出所有满足x2≡1mod&ThinSpace;&ThinSpace;nx^2\equiv1 \mod nx2≡1modn且0≤x<n0\ ...

  3. Cannot read property 'protocol' of undefined的原因和解决办法

    Cannot read property 'protocol' of undefined 原因:axios请求中的错误 1.请求地址写错了 2.没有引入http.js 3.引入http.js的时候,单 ...

  4. 证明解析函数u=c1 与 v=c2 正交

    方程u(x,y)=c1对应平面上的曲线, 求导dy/dx=  -ux/uy   类似有v曲线的dy/dx=-vx/vy   两者相乘,使用柯西-黎曼方程结果是-1 表示在相交点两者的切线互相垂直. 另 ...

  5. js,javascript,打印对象,object

    function writeObj(obj){ var description = ""; for(var i in obj){ var property=obj[i]; desc ...

  6. keras CNN解读

    loss是训练集损失值.  acc是训练集准确率.val_loss是测试集上的损失值,val_acc是测试集上的准确率. 用深度学习框架跑过实际问题的朋友一定有这样的感觉: 太神奇了, 它竟然能自己学 ...

  7. 从客户端(f="<zhaoyuntang.com")中检测到有潜在危险的 Request.Form 值。

    从客户端(f="<yi733.com")中检测到有潜在危险的 Request.Form 值. 解决办法1:在aspx页面头部加 ValidateRequest="f ...

  8. 通用的进程监控脚本process_monitor.sh使用方法

    不用做任何修改,即可用process_monitor.sh监控各种进程. 源码下载:https://github.com/eyjian/libmooon/blob/master/shell/proce ...

  9. oracle之简单总结

    视图: 作用:是数据库对象,是一个或多个表的或视图中导出的虚表,视图对应的数据并不是存储在视图中,而是存储在数据库中的数据表中. 视图的结构和数据是对数据表进行查询的结果. 优点: 1.简化数据操作. ...

  10. Spring AOP 中pointcut expression表达式

    原文地址——http://blog.csdn.net/qq525099302/article/details/53996344 Pointcut是指那些方法需要被执行”AOP”,是由”Pointcut ...