• Spring之AOP


    目录

    一、AOP概念

    AOP解决的问题

    AOP中关键性概念 

    如何实现AOP

    二、AOP使用

    准备工作

    前置通知

    后置通知

    ​编辑

    环绕通知

    异常通知

    过滤通知(适配器)

     三、总结


    一、AOP概念

    AOP:即面向切面编程

    AOP解决的问题

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

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

    AOP中关键性概念 

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

    目标(Target):被通知(被代理)的对象
    注1:完成具体的业务逻辑

    通知(Advice):非核心的业务代码,在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)
    注2:完成切面编程

    代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),
    注3:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的

    切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点。
                     (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)
        
    适配器(Advisor):相当于正则表达式,适配器=通知(Advice)+切入点(Pointcut)

    如何实现AOP

    目标对象只负责业务逻辑代码
    通知对象负责AOP代码,这二个对象都没有AOP的功能,只有代理对象才有

    二、AOP使用

    准备工作

    BookBiz.java

    1. package com.maomao.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. }

    异常类 PriceException.java

    1. package com.maomao.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. }

    BookBizImpl.java

    1. package com.maomao.aop.biz.impl;
    2. import com.maomao.aop.biz.BookBiz;
    3. import com.maomao.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. }

    前置通知

             实现org.springframework.aop.MethodBeforeAdvice接口
            买书、评论前加系统日志

    MyMethodBeforeAdvice.java

    1. package com.maomao.aop.advice;
    2. import java.lang.reflect.Method;
    3. import java.util.Arrays;
    4. import org.springframework.aop.MethodBeforeAdvice;
    5. /**
    6. * 前置通知
    7. * 买书、评论前加系统日志
    8. * @author Administrator
    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 methdName=arg0.getName();
    18. // 当前调用方法所传递参数
    19. String args=Arrays.toString(arg1);
    20. System.out.println("【系统日志】:"+clzName+"."+methdName+"被调用,传递的参数为:"+args);
    21. }
    22. }

    spring-context.xml 

    1. <bean class="com.maomao.aop.biz.impl.BookBizImpl" id="bookBiz">bean>
    2. <bean class="com.maomao.aop.advice.MyMethodBeforeAdvice" id="MyBefore">bean>
    3. <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
    4. <property name="target" ref="bookBiz">property>
    5. <property name="proxyInterfaces">
    6. <list>
    7. <value>com.maomao.aop.biz.BookBizvalue>
    8. list>
    9. property>
    10. <property name="interceptorName">
    11. <list>
    12. <value>myBeforevalue>
    13. list>
    14. property>
    15. bean>

    测试 

    1. package com.maomao.aop.demo;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. import com.maomao.aop.biz.BookBiz;
    4. public class Demo1 {
    5. @SuppressWarnings("resource")
    6. public static void main(String[] args) {
    7. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
    8. BookBiz bean=(BookBiz)context.getBean("bookBiz");
    9. bean.buy("aa", "abc", 99.9);
    10. bean.comment("aa", "123123");
    11. }
    12. }

    后置通知

             实现org.springframework.aop.AfterReturningAdvice接口
            买书返利(存在bug)

    每调用一次buy方法打印:“[销售返利][时间]返利3元。”

    MyAfterReturningAdvice.java

    1. package com.maomao.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. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    7. String targetName = target.getClass().getName();
    8. String methodName = method.getName();
    9. String params = Arrays.toString(args);
    10. String msg = "【返利通知:返利3元】:正在调用" + targetName + "." + methodName + ",携带的参数:" + params + ";目标对象所调用的方法的返回值:"
    11. + returnValue;
    12. System.out.println(msg);
    13. }
    14. }

    spring-context.xml 

    1. <bean class="com.cxy.aop.advice.MyAfterReturningAdvice" id="MyAfter">bean>

    运行结果

     

    环绕通知

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

    MyMethodInterceptor.java

    1. package com.maomao.aop.advice;
    2. import java.lang.reflect.Method;
    3. import java.util.Arrays;
    4. import org.aopalliance.intercept.MethodInterceptor;
    5. import org.aopalliance.intercept.MethodInvocation;
    6. public class MyMethodInterceptor implements MethodInterceptor {
    7. public Object invoke(MethodInvocation invocation) throws Throwable {
    8. Object target = invocation.getThis();
    9. Method method = invocation.getMethod();
    10. Object[] args = invocation.getArguments();
    11. String targetName = target.getClass().getName();
    12. String methodName = method.getName();
    13. String params = Arrays.toString(args);
    14. String msg = "【环绕通知】:正在调用->" + targetName + "." + methodName + ",携带的参数:" + params;
    15. System.out.println(msg);
    16. Object returnValue = invocation.proceed();
    17. String msg2 = "【环绕通知】:目标对象所调用的方法的返回值:" + returnValue;
    18. System.out.println(msg2);
    19. return returnValue;
    20. }
    21. }

     spring-context.xml 

    1. <bean name="MyFilterAdvice" class="com.maomao.aop.advice.MyMethodInterceptor">bean>

     

    异常通知

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

    MyThrowsAdvice.java

    1. package com.maomao.aop.advice;
    2. import org.springframework.aop.ThrowsAdvice;
    3. import com.maomao.aop.exception.PriceException;
    4. public class MyThrowsAdvice implements ThrowsAdvice {
    5. public void afterThrowing(PriceException ex ) {
    6. System.out.println("【异常通知】:价格输入错误,购买失败,请重新购买");
    7. }
    8. }

      spring-context.xml 

    1. <bean name="MyException" class="com.maomao.aop.advice.MyThrowsAdvice">bean>

    在原来的测试类改价格

    Demo1.java

    1. package com.maomao.aop.demo;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. import com.maomao.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("aa", "abc", -99.9);
    11. bean.comment("aa", "123123");
    12. }
    13. }

     

     

     

    过滤通知(适配器)

            org.springframework.aop.support.RegexpMethodPointcutAdvisor
            处理买书返利的bug

    1. <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
    2. id="MyAfterPlus">
    3. <property name="advice" ref="MyAfter">property>
    4. <property name="patterns" value=".*buy">property>
    5. bean>
    6. <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
    7. <property name="target" ref="bookBiz">property>
    8. <property name="proxyInterfaces">
    9. <list>
    10. <value>com.maomao.aop.biz.BookBizvalue>
    11. list>
    12. property>
    13. <property name="interceptorNames">
    14. <list>
    15. <value>MyBeforevalue>
    16. <value>MyAfterPlusvalue>
    17. <value>MyMethodvalue>
    18. <value>MyThrowsvalue>
    19. list>
    20. property>
    21. bean>
    22. beans>

     三、总结

    AOP面向切面编程

    主要作用:将核心的业务功能与非核心的业务功能进行分离;

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

    专业名词:通知、连接点、目标对象、切入点、代理、适配器

    日常开发通常的应用场景

      事物管理、日志功能

             事物的开启:前置通知

            事物的提交:后置通知

            事物的回滚:异常通知

  • 相关阅读:
    乙酰基六肽-1——促进黑色素合成,调节皮肤色素沉着
    Springboot 一个注解搞定返回参数key转换 【实用】
    深度剖析堆及代码实现
    爬虫初学篇——看完这些还怕自己入门不了?
    go排序相关操作
    Betaflight飞控之4.5版本配置文件调整
    美型和微整形SDK技术解决方案的新时代
    Hive效率优化记录
    JavaWeb核心、综合案例(详细!Web开发流程)
    花千骨歌曲大全 附简谱
  • 原文地址:https://blog.csdn.net/m12120426/article/details/126219562