• Spring——AOP


    目录

    一、Aop所解决的问题

    二、Aop的关键名词介绍

    三、前置通知

    四、后置通知

    五、环绕通知

    六、异常通知

    七、过滤通知

    八、知识总结


    一、Aop所解决的问题

    AOP:面向切面编程

    解决的问题:

    解决了需求的改变,造成了原有没必要改变的代码,需要去改变它;

    比如:书籍的增删改,本身只需要完成增删改的功能即可,这是如果需要添加日志功能,那么需要在原有的代码基础上,去修改添加日志功能,受牵连的方法就三个(add/edit/del)了。

    如书籍的增删改查:

    需求1:要求针对于书籍的增删改查进行监管,添加日志功能

    需求2:除了书籍管理的增删改查要添加日志功能,其他管理板块都要

    思考:不需要在原有的业务逻辑中添加任何代码,可以实现共性非业务功能

    二、Aop的关键名词介绍

    连接点(Joinpoint):

    程序执行过程中明确的点,如方法的调用,或者异常的抛出.

    目标(Target):

    被通知(被代理)的对象

    (注1:完成具体的业务逻辑)

    通知(Advice):

    在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)

    (注2:完成切面编程

    代理(Proxy):

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

     例子:外科医生+护士

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

    切入点(Pointcut):

    多个连接点的集合,定义了通知应该应用到那些连接点。

     (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)

        

    适配器(Advisor):

    适配器=通知(Advice)+切入点(Pointcut)

    三、前置通知

    以书籍的增删改查为例,

    实现org.springframework.aop.MethodBeforeAdvice接口

    买书、评论前加系统日志。

    首先准备工作:

    BookBiz :

    1. package com.ycx.aop.biz;
    2. public interface BookBiz {
    3. // 购书
    4. public boolean buy(String userName, String bookName, Double price);
    5. // 发表书评
    6. public void comment(String userName, String comments);
    7. }

     BookBizImpl :

    1. package com.ycx.aop.biz.impl;
    2. import com.ycx.aop.biz.BookBiz;
    3. import com.ycx.aop.exception.PriceException;
    4. public class BookBizImpl implements BookBiz {
    5. public BookBizImpl() {
    6. super();
    7. }
    8. public boolean buy(String userName, String bookName, Double price) {
    9. // 通过控制台的输出方式模拟购书
    10. if (null == price || price <= 0) {
    11. throw new PriceException("book price exception");
    12. }
    13. System.out.println(userName + " buy " + bookName + ", spend " + price);
    14. return true;
    15. }
    16. public void comment(String userName, String comments) {
    17. // 通过控制台的输出方式模拟发表书评
    18. System.out.println(userName + " say:" + comments);
    19. }
    20. }

    PriceException :

    1. package com.ycx.aop.exception;
    2. public class PriceException extends RuntimeException {
    3. public PriceException() {
    4. super();
    5. }
    6. public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
    7. super(message, cause, enableSuppression, writableStackTrace);
    8. }
    9. public PriceException(String message, Throwable cause) {
    10. super(message, cause);
    11. }
    12. public PriceException(String message) {
    13. super(message);
    14. }
    15. public PriceException(Throwable cause) {
    16. super(cause);
    17. }
    18. }


     spring-context.xml:

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xmlns:context="http://www.springframework.org/schema/context"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    9. <bean class="com.ycx.aop.biz.impl.BookBizImpl">bean>
    10. <bean class="com.ycx.aop.advice.MyMethodBeforeAdvice" id="myBefore">bean>
    11. <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
    12. <property name="target" ref="bookBiz">property>
    13. <property name="proxyInterfaces">
    14. <list>
    15. <value>com.ycx.aop.biz.BookBizvalue>
    16. list>
    17. property>
    18. <property name="interceptorNames">
    19. <list>
    20. <value>myBeforevalue>
    21. list>
    22. property>
    23. bean>
    24. beans>

     MyMethodBeforeAdvice :

    1. package com.ycx.aop.advice;
    2. import java.lang.reflect.Method;
    3. import java.util.Arrays;
    4. import org.springframework.aop.MethodBeforeAdvice;
    5. /**
    6. * 前置通知
    7. 买书、评论前加系统日志。
    8. * @author 杨总
    9. *
    10. */
    11. public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
    12. @Override
    13. public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
    14. // 目标对象的类名
    15. String clzName=arg2.getClass().getName();
    16. // 当前调用的方法是
    17. String methodName=arg0.getName();
    18. // 当前调用方法所传递参数
    19. String args=Arrays.toString(arg1);
    20. System.out.println("【系统日志】:"+clzName+"."+methodName+"被调用,传递的参数为:"+args);
    21. }
    22. }

     Demo1 :

    1. package com.ycx.aop.test;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. import com.ycx.aop.biz.BookBiz;
    4. public class Demo1 {
    5. @SuppressWarnings("resource")
    6. public static void main(String[] args) {
    7. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
    8. // BookBiz bean =(BookBiz) context.getBean("bookBiz");
    9. BookBiz bean =(BookBiz) context.getBean("bookProxy");
    10. bean.buy("杨总", "一日暴富", 999);
    11. bean.comment("阿颜", "好");
    12. }
    13. }

    四、后置通知

    实现org.springframework.aop.AfterReturningAdvice接口

    买书返利(存在bug)

    MyAfterReturningAdvice :

    1. package com.ycx.aop.advice;
    2. import java.lang.reflect.Method;
    3. import java.util.Arrays;
    4. import org.springframework.aop.AfterReturningAdvice;
    5. public class MyAfterReturningAdvice implements AfterReturningAdvice{
    6. @Override
    7. public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
    8. // 目标对象的类名
    9. String clzName=arg3.getClass().getName();
    10. // 当前调用的方法是
    11. String methodName=arg1.getName();
    12. // 当前调用方法所传递参数
    13. String args=Arrays.toString(arg2);
    14. System.out.println("【买书返利】:"+clzName+"."+methodName+"被调用,传递的参数为:"+args+";目标对象方法返回值为:"+arg0);
    15. }
    16. }

     spring-context.xml:

    1. <bean class="com.ycx.aop.advice.MyAfterReturningAdvice" id="myAfter">bean>
    1. "interceptorNames">
    2. <list>
    3. <value>myBeforevalue>
    4. <value>myAftervalue>
    5. list>

    五、环绕通知

    org.aopalliance.intercept.MethodInterceptor

    类似拦截器,会包括切入点,目标类前后都会执行代码。

    MyMethodInterceptor :

    1. package com.ycx.aop.advice;
    2. import java.util.Arrays;
    3. import org.aopalliance.intercept.MethodInterceptor;
    4. import org.aopalliance.intercept.MethodInvocation;
    5. /**
    6. * 环绕通知=前置通知+后置通知
    7. * @author 杨总
    8. *
    9. */
    10. public class MyMethodInterceptor implements MethodInterceptor{
    11. @Override
    12. public Object invoke(MethodInvocation arg0) throws Throwable {
    13. // 目标对象的类名
    14. String clzName=arg0.getThis().getClass().getName();
    15. // 当前调用的方法是
    16. String methodName=arg0.getMethod().getName();
    17. // 当前调用方法所传递参数
    18. String args=Arrays.toString(arg0.getArguments());
    19. System.out.println("【环绕通知】:"+clzName+"."+methodName+"被调用,传递的参数为:"+args);
    20. //方法的返回值 执行目标方法 bookBiz.buy(...,...,...);
    21. Object rs = arg0.proceed();
    22. System.out.println("【环绕通知】:目标对象方法返回值为:"+rs);
    23. return rs;
    24. }
    25. }

      spring-context.xml:

    1. <bean class="com.ycx.aop.advice.MyMethodInterceptor" id="myMethod">bean>
    1. "interceptorNames">
    2. <list>
    3. <value>myBeforevalue>
    4. <value>myAftervalue>
    5. <value>myMethodvalue>
    6. list>

    六、异常通知

    org.springframework.aop.ThrowsAdvice

    出现异常执行系统提示,然后进行处理。价格异常为例

     MyThrowsAdvice :

    1. package com.ycx.aop.advice;
    2. import org.springframework.aop.ThrowsAdvice;
    3. import com.ycx.aop.exception.PriceException;
    4. /**
    5. * 关于过滤通知
    6. * 相较于前置通知、后置通知、环绕通知有一个非常大的区别
    7. * 前面三大通知都需要实现其中的方法
    8. * 环绕通知则不需要,但是它的方法名又是固定的
    9. * @author 杨总
    10. *
    11. */
    12. public class MyThrowsAdvice implements ThrowsAdvice{
    13. public void afterThrowing(PriceException p) {
    14. System.out.println("【异常通知】:当前价格发生异常,那么执行此处代码块");
    15. }
    16. }

      spring-context.xml:

    1. <bean class="com.ycx.aop.advice.MyThrowsAdvice" id="myThrows">bean>
    1. "interceptorNames">
    2. <list>
    3. <value>myBeforevalue>
    4. <value>myAftervalue>
    5. <value>myMethodvalue>
    6. <value>myThrowsvalue>
    7. list>

    七、过滤通知

    org.springframework.aop.support.RegexpMethodPointcutAdvisor

    处理买书返利的bug

       spring-context.xml:

    1. <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="myAfterPlus">
    2. <property name="advice" ref="myAter">property>
    3. <property name="pattern" value=".buy">property>
    4. bean>
    1. <property name="interceptorNames">
    2. <list>
    3. <value>myBeforevalue>
    4. <value>myAfterPlusvalue>
    5. <value>myMethodvalue>
    6. <value>myThrowsvalue>
    7. list>
    8. property>

    综上所有运行效果:

     

    八、知识总结

    Aop面向切面编程

            主要作用:

            将核心的业务功能与非核心的业务功能进行分离

            将核心的业务功能写到目标对象中,将非核心的业务功能写到通知中

    专业名词:

            通知、连接点、目标对象、切入点、代理、适配器

    日常开发中通常的应用场景:

            事务管理、日志

            事务的开启:前置通知

            事务的提交:后置通知

            事务的回滚:异常通知

  • 相关阅读:
    【Linux】5.0基础IO
    Docker实战:docker compose 搭建Rocketmq
    一篇文章带你了解轻量级Web服务器——Nginx简单入门
    Linux 搭建本地镜像源(CentOS 离线 yum)
    mysql8.0笔记
    mysql分组concat() concat_ws() group_concat()
    为什么只会编程的程序员无法成为优秀的开发者?
    高数笔记05:不定积分与定积分
    HTML+CSS静态网页设计:(房地产网站设计与实现6页)
    RestSharp使用
  • 原文地址:https://blog.csdn.net/weixin_65808248/article/details/126213418