登录/注册
唐某
2948
5
25
浏览量
粉丝
关注
spring之AOP笔记(IDEA)
唐某
2020-11-14 22:55:19
82
0

spring之AOP笔记(IDEA)

什么是AOP(面向切面)

传统代码遇见的问题

代码臃肿冗余,复用性不高,模块之间耦合度高

初步解决方法

将大量重复使用的代码块抽取成一个个的方法,降低代码冗余,但是这解决不了根本性的问题,即代码的耦合度没有降低,

如果需求变了,那么我们肯定是要修改源代码,如果代码庞大,这种重复性的修改无疑做着无用功,所以AOP思想诞生了

AOP思想

首先AOP是基于动态代理的思想,在不改变原有类(被代理类)**的前提下,创建新生的类(代理类)**来增强原有的类

起名叫AOP呢,形象的说,AOP思想是将需求代码块插入原有类

基于Annotation和bean.xml

bean.xml
<?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="mySpring"></context:component-scan>
    <!--开启注解aop控制-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
创建目标类接口
package mySpring.service;

/**
 * 模拟业务层
 */
public interface IAccountService {
    void saveAccount();
    void updateAccount(int id);
    int deleteAccount();
}
创建目标类
package mySpring.service.impl;

import mySpring.service.IAccountService;
import org.springframework.stereotype.Service;

@Service("accountService")
public class AccountService implements IAccountService {
    @Override
    public void saveAccount() {
        System.out.println("saveAccount......");
    }

    @Override
    public void updateAccount(int id) {
        System.out.println("updateAccount......" + id);

    }
    @Override
    public int deleteAccount() {
        System.out.println("deleteAccount......");
        return 0;
    }
}

先在有新的需求,想在每个方法执行前输入一些东西(这里以日志输出为例)

需要为这个目标类(被代理对象)找到一个代理类

创建代理类Logger
package mySpring.utils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component("logger")
@Aspect//申明为切面类(代理类)
public class Logger {
    //    代理谁?表达式指定
    @Pointcut("execution(* mySpring.service.IAccountService.*(..))")
    private void pt() {
    }

    /**
      *    执行相关方法前的操作
      *    前置
      */
    @Before("pt()")    //指定切点pointcut
    public void beforeMethod() {
        System.out.println("前置");
    }

    /**
      *    执行相关方法后的操作
      *    后置
      */
    @AfterReturning("pt()")
    public void returnMethod(JoinPoint joinPoint) throws Throwable {
        System.out.println("后置");
    }

    /**
      *    执行相关方法异常时会加的操作
      *    异常
      */
    @AfterThrowing("pt()")
    public void throwMethod(JoinPoint joinPoint) throws Throwable {
        System.out.println("异常");

    }

    /**
      *    执行相关方法最终结束的操作
      *    最终
      */
    @After("pt()")
    public void afterMethod(JoinPoint joinPoint) throws Throwable {
        System.out.println("最终");
    }

    /**
      *    环绕
      */
    @Around("pt()")
    public Object aroundMethod(ProceedingJoinPoint pjp) {
        Object value = null;
        try {
            Object[] args = pjp.getArgs();
            System.out.println("前置");
            value = pjp.proceed(args);
            System.out.println("后置");
        } catch (Throwable throwable) {
            System.out.println("异常");
            throwable.printStackTrace();
        } finally {
            System.out.println("最终");
        }
        return value;
    }
}
测试类
package mySpring;

import mySpring.service.IAccountService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService service = context.getBean("accountService", IAccountService.class);
        service.updateAccount(10);
    }
}
运行结果(非环绕)
image-20200812184953900

可见,最终后置两个增强点位置反了(Spring的bug)

运行结果(环绕)
image-20200812185327654

正常输出,所以建议使用Around方式通知(实现切面)

基于纯bean.xml

bean.xml
<?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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="accountService" class="mySpring.service.impl.AccountService"></bean>
    <bean id="logger" class="mySpring.utils.Logger"></bean>

    <aop:config>
        <aop:pointcut id="pt" expression="execution(* mySpring.service.IAccountService.*(..))"/>
        <aop:aspect id="logAdvice" ref="logger">
                      <!--四种位置-->
                        <aop:before method="beforeMethod" pointcut-ref="pt"></aop:before>
                        <aop:after-returning method="returnMethod" pointcut-ref="pt"></aop:after-returning>
                        <aop:after-throwing method="throwMethod" pointcut-ref="pt"></aop:after-throwing>
                        <aop:after method="afterMethod" pointcut-ref="pt"></aop:after>
<!--            <aop:around method="aroundMethod" pointcut-ref="pt"></aop:around>-->
        </aop:aspect>
    </aop:config>
</beans>
Logger类
package mySpring.utils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class Logger {
    public void beforeMethod() {
        System.out.println("前置");
    }

    public void returnMethod(JoinPoint joinPoint) throws Throwable {
        System.out.println("后置");
    }

    public void throwMethod(JoinPoint joinPoint) throws Throwable {
        System.out.println("异常");

    }

    public void afterMethod(JoinPoint joinPoint) throws Throwable {
        System.out.println("最终");
    }

    public Object aroundMethod(ProceedingJoinPoint pjp){
        Object value = null;
        try {
            Object[] args = pjp.getArgs();
            //    调用之前位置出现的是前置想要增强代码块
            System.out.println("前置");

            //    显式调用目标类的方法
            value = pjp.proceed(args);

            //    调用之后位置出现的是后置想要增强代码块
            System.out.println("后置");
        } catch (Throwable throwable) {
            System.out.println("异常");
            throwable.printStackTrace();
        } finally {
            System.out.println("最终");
        }
        return value;
    }
}
运行结果

同上,且没有bug

原文:https://search.gitee.com/?skin=rec&type=repository&q=java%E7%AC%94%E8%AE%B0&repo=&reponame=

暂无评论