• 使用SpringAOP


    面向切面编程

    Aspect Oriented Programming(AOP)面向切面编程是一种范式和思想,并不是特指某一种编程语言。下面这句话是知乎上的一个总结:

    在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

    可以看到,将某一种通用的非功能代码,从业务逻辑中剥离,形成一个切面并在指定的时机切入到指定位置上的思想,就是AOP得思想。同样,减少重复代码、专注业务、分离功能代码和非功能代码就是AOP的主要职责。SpringAOP框架可以在运行时将切面代码植入切点,在功能代码周围切入非功能代码,达到不侵入业务代码的情况下,完成指定操作。可以说,AOP是OOP的延续和补充,大锤砸墙、小锤抠缝,配合好了才能达到想要的效果。

    应用场景

    1. 权限控制
    2. 缓存控制
    3. 事物控制
    4. 审计日志
    5. 性能监控
    6. 分布式追踪
    7. 异常处理

    AOP的主要应用场景就是在某一业务逻辑的前后(切入点),插入一些与业务逻辑无关却必要的工作(切面)。想象一下在某一层方法前后,都添加调用该方法的Log信息,以往的做法会在每个方法前后分别添加一行log.info(...),像这样:

    funA (args) {
        log.info(funA start);
        {funAbody}
        log.info(funA end);
    }

    可是这样会产生大量重复代码,因为每个方法前后都需要添加这两行代码。

    Don’t Repeat Yourself.

    这是在我们常听到的一句话,也是我们义不容辞的使命。在学习面向对象后,就会想,应该可以把这个重复的代码可以抽象到父类里面,子类实现父类的抽象方法,像这样:

    abstract class BaseClass {
        fun (args) {
            log.info(funA start);
            funA(args);
            log.info(funA end);
        }
        abstract funA(args);
    }

    这样代码是少了,可是使用的灵活性上面收到了很大的限制。我们必须要继承父类才可以实现方法,同时方法调用时也只能通过父类的包装方法来完成调用。在使用的时候就会很不方便。于是,面向切面就出现了。AOP解决此类问题的方法是把这些与方法逻辑无关,却对整体有帮助的代码,抽象到一个切面中,切入到每个方法调用的前后。这样,这些重复的代码成功的完成了抽象,剩下的就只需要在合适的切入点将这些切面切入到方法调用前后。

    AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。

    SpringAOP

    SpringAOP注解

    SpringAOP使用示例

    想象如下场景:想要对Service的方法调用前,对参数进行校验。接下来通过一下的代码,来看一下在SpringAOP中怎么将校验的代码织入到制定的位置:

    /**
     * 定义一个切面,切点和要织入的方法
     * 1 使用@Conponent将类托管给Spring (必须要有,不然不会织入切面代码)
     * 2 使用@Aspect注解声明切面
     * 3 使用@Pointcut  声明切点(代码织入点)
     * 4 声明Advice: 注解声明织入代码时机(@After,@Before,@Around,@AfterThrowing,@AfterReturning)
     *              方法体内写具体的织入代码
     */
    @Component
    @Aspect
    public class ParamCheck {
    
        @Pointcut("within(com.lieh666.cloud.aop..*Service*)")
        public void matchPak(){}
    
        @Before(value = "matchPak()")
        public void checkParamBefore() {
            System.out.println("####check param before");
        }
    
        @After(value = "matchPak()")
        public void checkParamAfter() {
            System.out.println("####check param after");
        }
    }
    
    /**
     * 定义一个被切入的类,此次为Service
     */
    @Service
    public class UserService {
        public void sayHi (String name) {
            System.out.println("hi," + name);
        }
    }
    
    /**
     * 实现一个Test来测试是否织入成功
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = {SpringAOPService.class})
    public class UserServiceTest {
        @Autowired
        UserService userService;
    
        @Test
        public void sayHi() throws Exception {
            userService.sayHi("lieh");
        }
    
    }

    原理

    AOP主要是基于动态代理来实现的,同时AOP也是动态代理模式的一种典型应用。Spring在此基础上加以扩展,添加了Pointcut、Advisor等一些接口使其更加灵活。

    SpringAOP基于以下两种实现方式:
    1. jdk动态代理
    2. Cglib动态代理

    SpringAOP对两种代理方式的选择策略如下:
    1. 如果目标对象实现了接口,则默认选择JDK动态代理
    2. 如果目标对象没有实现接口,则采用Cglib进行代理
    3. 如果目标对象实现了接口,且强制Cglib代理,则使用Cglib代理

    AOP的主要思想,就是拆分、解耦功能模块和非功能模块。并且提高了非功能模块代码的复用。

    问题及注意事项

    1、区分业务逻辑代码和非业务逻辑代码,不要将业务逻辑代码放在AOP中,不然会导致业务功能不清晰。

    2、不能代理内部方法调用,内部调用会使用this关键字,而不是生成的代理类。

    3、不能代理private、final、static方法。

    参考文章:
    - JavaWeb过滤器.监听器.拦截器
    - 什么是面向切面编程AOP? - 知乎
    - java动态代理原理及解析

  • 相关阅读:
    23种设计模式
    Java实现动态代理的两种方式
    jQuery easyui combobox级联及内容联想
    使用Spring MVC统一异常处理
    springmvc下使用kaptcha做验证码
    Hadoop及spark介绍
    jQuery easyui 之 expend row
    Http 1.1协议
    公钥、私钥、CA认证、数字签名、U盾
    SOA架构介绍
  • 原文地址:https://www.cnblogs.com/enhe/p/12141705.html
Copyright © 2020-2023  润新知