SpringAop

简介: SpringAop

1.Spring的Aop特点

例如:

网上书城项目、

书籍管理模块

场景一:客户使用系统,上架了国家明令禁止的书籍

场景二:对与平台方而言客户已下单并已付款,工作人员出于私心,将货品拿了,从中牟利

所以,所有系统都会添加一个日志功能,也就是每一个业务功能模块都会有一个日志文件

Aop处理非业务核心代码

2.Aop的中关键概念(Aop的专业术语):

连接点(joinpoint):程序执行过程中明确地点,如方法的调用,或者异常的抛出,

目标:被通知(被代理)的对象

注:完整的具体业务逻辑

通知(advice):在某个特定的连接点上执行的动作,同时advice也是程序代码的具体实现,

例如一个实现日志记录的代码(通知在有些书上也成为处理)

注2:完成切面编程

代理:将通知应用到目标对象后创建的对象(代理=目标+通知)

例子:外科医生+护士

注3:只有代理对象才有Aop功能,而Aop的代码是写在通知方法里面的

切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点(也将poiintcut理解成一个条件,此条件决定了容器在说明情况下将通知和目标组合成代理返回给外部程序)

适配器(Advisor):适配器=通知(advice)+切入点(pointcut)

总结:面向切面编程,使代码原有的从上倒下的执行顺序做出改变,加入了spring的Aop的面向切面编程这个思想,那么我们代码的执行顺序则不再是从上到下,而是走到了目标执行对象的时候要查看是否有前置通知,如果有则先执行前置通知在执行目标方法,如果没有则直接执行目标方法,那么再看目标执行代码是否有后置通知,如果有则执行后置通知,如果没有则代码执行完了

3.Spring中的专业术语所对应的案例

首先我们准备五个类

package xzs.aop.biz;
public interface BookBiz {
  // 购书
  public boolean buy(String userName, String bookName, Double price);
  // 发表书评
  public void comment(String userName, String comments);
}
package xzs.aop.biz.impl;
import xzs.aop.biz.BookBiz;
import xzs.aop.biz.exceptio.PriceException;
public class BookBizImpl implements BookBiz {
  public BookBizImpl() {
    super();
  }
  public boolean buy(String userName, String bookName, Double price) {
    // 通过控制台的输出方式模拟购书
    if (null == price || price <= 0) {
      throw new PriceException("book price exception");
    }
    System.out.println(userName + " buy " + bookName + ", spend " + price);
    return true;
  }
  public void comment(String userName, String comments) {
    // 通过控制台的输出方式模拟发表书评
    System.out.println(userName + " say:" + comments);
  }
}

 

package xzs.aop.biz.exceptio;
public class PriceException extends RuntimeException {
  public PriceException() {
    super();
  }
  public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
    super(message, cause, enableSuppression, writableStackTrace);
  }
  public PriceException(String message, Throwable cause) {
    super(message, cause);
  }
  public PriceException(String message) {
    super(message);
  }
  public PriceException(Throwable cause) {
    super(cause);
  }
}

3.1前置通知

package xzs.aop.biz.advice;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
/**
 * 买书、评论前加系统日志
 * @author Administrator
 *
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
  @Override
  public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//    在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去
    String target = arg2.getClass().getName();//那个类
    String methodName = arg0.getName();//调用什么方法
    String args = Arrays.toString(arg1);//传递了什么参数
    System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了");
  }
}

Sprint-context.xml中配置

 <bean class="xzs.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
<bean class="xzs.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean>
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
        <property name="target" ref="bookBiz"></property>
         <property name="proxyInterfaces">
             <list>
                 <value>xzs.aop.biz.BookBiz</value>
             </list>
         </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
                <value>methodBeforeAdvice</value>
            </list>
        </property>
    </bean>

测试:

 

3.2后置通知

package xzs.aop.biz.advice;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.AfterReturningAdvice;
/**
 * 买书返利
 * @author Administrator
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {
  @Override
  public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
    String target = arg3.getClass().getName();
    String methodName = arg1.getName();
    String args = Arrays.toString(arg2);
    System.out.println("【后置通知:买书返利】:"+target+"."+methodName+"("+args+")被调用了,"+"该方法被调用后的返回值为:"+arg0);
  }
}

spring-context.xml中

   <bean class="xzs.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
<bean class="xzs.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean>
    <bean class="xzs.aop.biz.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
        <property name="target" ref="bookBiz"></property>
         <property name="proxyInterfaces">
             <list>
                 <value>xzs.aop.biz.BookBiz</value>
             </list>
         </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
                <value>methodBeforeAdvice</value>
                <value>myAfterReturningAdvice</value>
            </list>
        </property>
    </bean>

运行:

 

3.3环绕通知

package xzs.aop.biz.advice;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 * 环绕通知
 *  包含了前置和后置通知
 * 
 * @author Administrator
 *
 */
public class MyMethodInterceptor implements MethodInterceptor {
  @Override
  public Object invoke(MethodInvocation arg0) throws Throwable {
    String target = arg0.getThis().getClass().getName();
    String methodName = arg0.getMethod().getName();
    String args = Arrays.toString(arg0.getArguments());
    System.out.println("【环绕通知调用前:】:"+target+"."+methodName+"("+args+")被调用了");
//    arg0.proceed()就是目标对象的方法
    Object proceed = arg0.proceed();
    System.out.println("【环绕通知调用后:】:该方法被调用后的返回值为:"+proceed);
    return proceed;
  }
}
    <bean class="xzs.aop.biz.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
    <bean class="xzs.aop.biz.advice.MyMethodInterceptor" id="interceptor"></bean>
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
        <property name="target" ref="bookBiz"></property>
         <property name="proxyInterfaces">
             <list>
                 <value>xzs.aop.biz.BookBiz</value>
             </list>
         </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
<!--                <value>methodBeforeAdvice</value>-->
<!--                <value>myAfterReturningAdvice</value>value-->
                <value>interceptor</value>
            </list>
        </property>
    </bean>

运行:

 

3.4异常通知

package com.zking.aop.advice;
import org.springframework.aop.ThrowsAdvice;
import com.zking.aop.exception.PriceException;
/**
 * 出现异常执行系统提示,然后进行处理。价格异常为例
 * @author Administrator
 *
 */
public class MyThrowsAdvice implements ThrowsAdvice {
  public void afterThrowing(PriceException ex) {
    System.out.println("【异常通知】:当价格发生异常,那么执行此处代码块!!!");
  }
}

 

<bean class="xzs.aop.biz.advice.MyThrowsAdvice" id="myThrowsAdvice"></bean>
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
        <property name="target" ref="bookBiz"></property>
         <property name="proxyInterfaces">
             <list>
                 <value>xzs.aop.biz.BookBiz</value>
             </list>
         </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
<!--                <value>methodBeforeAdvice</value>-->
<!--                <value>myAfterReturningAdvice</value>value-->
<!--                <value>interceptor</value>-->
                <value>myThrowsAdvice</value>
            </list>
        </property>
    </bean>

 

3.5过滤通知

在spring的配置文件中直接配置就行

 <bean class="xzs.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
<bean class="xzs.aop.biz.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean>
    <bean class="xzs.aop.biz.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
    <bean class="xzs.aop.biz.advice.MyMethodInterceptor" id="interceptor"></bean>
    <bean class="xzs.aop.biz.advice.MyThrowsAdvice" id="myThrowsAdvice"></bean>
   <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor">
      <property name="advice" ref="myAfterReturningAdvice"></property>
<property name="pattern" value=".*buy"></property>
   </bean>
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
        <property name="target" ref="bookBiz"></property>
         <property name="proxyInterfaces">
             <list>
                 <value>xzs.aop.biz.BookBiz</value>
             </list>
         </property>
<!--配置通知-->
        <property name="interceptorNames">
            <list>
                <value>methodBeforeAdvice</value>
<!--                <value>myAfterReturningAdvice</value>value-->
                <value>regexpMethodPointcutAdvisor</value>
                <value>interceptor</value>
                <value>myThrowsAdvice</value>
            </list>
        </property>
    </bean>

测试:

过滤前:

以上对比可看出如果没有过滤评论就会出来买书返利,很显然不符合常理

4.总结

aop是面向切面的编程,程序由上至下,但是aop面向切面编程不是,aop得到程序执行,

首先当程序执行到目标对象的目标方法时,如果连接点上由前置通知,则先执行前置通知,

在执行目标方法,如果没有前置则继续执行目标方法,再查看目标方法👆是否有后置通知代码:

前置通知,环绕通知,异常通知,过滤通知,代码都是非业务核心代码:如日志,事务的管理(开启,提交,回滚)


相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
传感器 安全 数据处理
基于振弦采集仪的工程监测技术探索
随着工程建设的日益发展,对工程监测的需求也越来越迫切。工程监测是保障工程质量和安全的重要手段。而基于振弦采集仪的工程监测技术,由于其高精度、高灵敏度和实时性等特点,正逐渐成为工程监测领域的重要技术。
基于振弦采集仪的工程监测技术探索
|
资源调度 JavaScript 前端开发
【TypeScript】TS 看这一篇就够了
【TypeScript】TS 看这一篇就够了
2281 0
|
编解码 前端开发 UED
移动优化:提升用户体验的关键
在移动设备成为人们生活中不可或缺的一部分之后,移动优化已经成为现代网站和应用程序开发的重要组成部分。优化网站或应用程序以适应小屏幕和有限的网络带宽可以显著提高用户体验,增加用户满意度。本博客将深入探讨移动优化的核心概念、最佳实践以及如何确保您的项目在移动设备上表现出色。
552 0
|
运维 Prometheus 监控
从文化到实践:DevOps的基本概念与核心实践详解
从文化到实践:DevOps的基本概念与核心实践详解
591 5
|
Kubernetes Linux Docker
kubeadm安装Kubernetes
kubeadm安装Kubernetes
296 0
|
数据采集 XML 缓存
心得经验总结:爬虫(爬虫原理与数据抓取)
心得经验总结:爬虫(爬虫原理与数据抓取)
634 0
|
数据安全/隐私保护 Python
Python正则表达式:强大的文本处理工具
Python正则表达式:强大的文本处理工具
223 1
|
存储 安全 Java
Java.security包中的KeyStore类详解
Java.security包中的KeyStore类详解
1083 0
|
机器学习/深度学习 数据可视化 C语言
多分类混淆矩阵详解
多分类混淆矩阵详解
2132 0
|
Java
java 主线程破获子线程异常
java 主线程破获子线程异常
187 0

热门文章

最新文章