文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java AOP篇

2023-10-23 08:53

关注

目录

        一、什么是AOP

         二、为什么使用AOP

        三、AOP的体系结构

        四、AOP原理

        五、AOP能做什么

        六、AOP案例-- 使用AOP模拟事务管理

        6.1 创建一个Spring工程

        6.2 引入相关的依赖

        6.3 写spring的配置文件。  

        6.4 创建service接口以及实现类

        6.5 定义切面类

        6.6 测试

        6.7 aop中的通知类型

        七、AOP案例--使用注解切点

        7.1 创建Controller包

        7.2 定义切面    

        7.3 修改Spring配置文件

         八、AOP案例--使用自定义注解

        8.1 自定义注解

        8.2 使用自定义注解

        8.3 定义切面

        8.4 测试


        一、什么是AOP

        AOP(Aspect Oriented Programming)面向切面思想,是Spring的三大核心思想之一(AOP-面向切面、IOC-控制反转、DI-依赖注入)

        AOP,一般成为面向切面,作为面向对象OOP的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块之间的耦合度,提高了系统的可维护性。可用于权限认证,日志和事务处理.         

         二、为什么使用AOP

        Java是一个面向对象(OOP)的编程语言,但它有个弊端就是当需要为多个不具有继承关系的对象引入一个公共行为时,例如日志记录、权限校验、事务管理、统计等功能,只能在每个对象里都引用公共行为,这样做不便于维护,而且有大量重复代码,AOP的出现弥补了OOP的这点不足

        例如:

        有多少个业务操作,就要写多少重复的校验和日志记录代码,这显然是无法接受的。当然用面向对象的思想,可以把这些重复的代码抽离出来,写成公共方法,就是下面这样

         

        代码冗余和可维护性的问题得到了解决,但每个业务方法中依然要依次手动调用这些公共方法,也是略显繁琐。 有没有更好的方式呢?有的,那就是AOP,AOP将权限校验、日志记录等非业务代码完全提取出来,与业务代码分离,并寻找节点切入业务代码中 。         

        动态代理 :

        三、AOP的体系结构

        AOP要做的三件事是:在哪里切入,什么时候切入,切入后做什么事

        在哪里切入:就是权限校验等非业务操作在哪些业务代码中执行

        什么时候切入:就是业务代码执行前还是执行后

        切入后做什么事:比如做权限校验,日志记录等等

 

  • Pointcut:切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。

  • Advice:处理,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。

  • Aspect:切面,即Pointcut和Advice。

  • Joint point:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。

  • Weaving:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。

        四、AOP原理

        之前提到JDK代理和Cglib代理两种动态代理,优秀的Spring框架把两种方式在底层都集成了进去,无需担心自己去实现动态生成代理。那么Spring是如何生成代理对象的?创建容器对象的时候,根据切入点表达式拦截的类,生成代理对象。如果目标对象有实现接口,使用jdk代理如果目标对象没有实现接口,则使用Cglib代理。然后从容器获取代理后的对象,在运行期植入"切面"类的方法。如果目标类没有实现接口,且class为final修饰的,则不能进行Spring AOP编程

        

        封装了JDK代理和Cglib代理。 当被代理的类实现了接口,则使用JDK代理。如果没有实现接口则使用Cglib代理。

        类没有实现接口且使用final修饰 不能使用AOP.

        五、AOP能做什么

  • Spring声明式事务管理配置 [事务管理]

  • Controller层的参数校验

  • 使用Spring AOP实现MySQL数据库读写分离案例分析

  • 在执行方法前,判断是否具有权限

  • 对部分函数的调用进行日志记录。监控部分重要函数,若抛出指定的异常,可以以短信或邮件方式通知相关人员

  • 信息过滤,页面转发等等功能。

        什么是事务?

        有一系列动作组成的一个单元,这些动作要么全部执行,要么全部不执行。

        例子: 张三给李四转账。[1] 张三减钱 [2]李四加钱。

                mysql是支持事务的。

        六、AOP案例-- 使用AOP模拟事务管理

        6.1 创建一个Spring工程

        

        6.2 引入相关的依赖

    4.0.0    com.wjk    java-11-11-AOP    1.0-SNAPSHOT                                org.springframework            spring-webmvc            5.2.9.RELEASE                                    org.springframework            spring-aspects            5.2.9.RELEASE                            com.fasterxml.jackson.core            jackson-databind            2.13.2.2                            com.alibaba            fastjson            1.2.75            

        6.3 写spring的配置文件。  

                

        6.4 创建service接口以及实现类

package com.wjk;public interface IUserService {    public void save();}
package com.wjk.imp;import com.wjk.IUserService;import org.springframework.stereotype.Service;@Servicepublic class UserService implements IUserService {    public void save() {        System.out.println("保存用户");    }}
package com.wjk.imp;import com.wjk.IUserService;import org.springframework.stereotype.Service;@Servicepublic class OrderService {    public void save() {        System.out.println("保存订单");    }}

        6.5 定义切面类

@Component //校验spring容器来创建该类对象。@Aspect  //标记该类为切面类public class TransactionAop {          @Pointcut("execution(* com.ykq.aop01.service.impl.*.*(..))")     private void transationAdvice(){}     @Before("transationAdvice()")     public void before(){         System.out.println("前置通知---开启事务");     }}

        6.6 测试

public class Test {    public static void main(String[] args) {        //读取spring配置文件        ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");        //该类使用了接口---使用JDK动态代理        IUserService userService = app.getBean(IUserService.class);        userService.save();        //该类没有实现接口---切面使用cglib动态代理        OrderService orderService = app.getBean(OrderService.class);        orderService.save();    }}

        6.7 aop中的通知类型

                

package com.wjk.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;@Component  //校验spring容器来创建该类对象@Aspect     //标记该类为切面类public class TransactionAop {        @Pointcut("execution(* com.wjk.imp.*.*(..))")    public void transationAdvice(){    };        @Before("transationAdvice()")    public void before(){        System.out.println("前置处理--开启事务");    }        @After("transationAdvice()")    public void after(){        //理解为方法执行完毕        System.out.println("后置处理--提交事务");    }        @AfterReturning("transationAdvice()")    public void afterReturning(){        System.out.println("后置返回通知");    }        @AfterThrowing("transationAdvice()")    public void afterThrowing(){        System.out.println("异常处理,事务回滚");    }    @Around("transationAdvice()")    public void around(ProceedingJoinPoint joinPoint){        System.out.println("环绕通知前");        try {            joinPoint.proceed();//回调连接点方法            System.out.println("环绕方法执行完毕");        } catch (Throwable throwable) {            System.out.println("环绕通知-异常");        }finally {            System.out.println("环绕通知-执行最终");        }    }}

        七、AOP案例--使用注解切点

        在使用GetMapping注解的方法上,使用切面

        7.1 创建Controller包

package com.wjk.controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/aop")public class HelloController {    @GetMapping("/getTest")    public String getTest(){        System.out.println("执行了getTest");        return "getTest";    }    @PostMapping("/postTest")    public String postTest(){        System.out.println("执行了postTest");        return "postTest";    }}

        7.2 定义切面    

package com.wjk.aspect;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Component@Aspectpublic class LogAdvice {    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")    private void logAdvice(){}    @Before("logAdvice()")    public void before(){        System.out.println("添加getTest的前置日志");    }}

        7.3 修改Spring配置文件

                            

         八、AOP案例--使用自定义注解

        8.1 自定义注解

package com.wjk.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(value = ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface MyPermission {    String value() default "";}

        8.2 使用自定义注解

package com.wjk.controller;import com.wjk.annotation.MyPermission;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;import java.util.List;@RestController@RequestMapping("/user")public class UserController {    @RequestMapping("/list")    @MyPermission("list")    public String list(){        System.out.println("查询所有用户");        return "list";    }    @PostMapping("/save")    @MyPermission("save")    public String save(){        System.out.println("添加用户");        return "save";    }}

        8.3 定义切面

package com.wjk.aspect;import com.wjk.annotation.MyPermission;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;@Component@Aspectpublic class PermissionAdvice {    //定义切点    @Pointcut("@annotation(com.wjk.annotation.MyPermission)")    public void permission(){    }    private List permission=new ArrayList();    public  PermissionAdvice(){        permission.add( "list");        permission.add("delete");        permission.add("update");    }    @Around("permission()")    public Object before(ProceedingJoinPoint joinPoint) throws Throwable {        //得到连接点执行的方法对象        MethodSignature signature= (MethodSignature) joinPoint.getSignature();        Method method = signature.getMethod();        //得到方法上的注解        MyPermission annotation = method.getAnnotation(MyPermission.class);        if (annotation!=null){            //获取注解属性的value值            String value = annotation.value();            if (!permission.contains(value)){                return "quanxianbuzu";            }        }        return joinPoint.proceed();    }}

        8.4 测试

来源地址:https://blog.csdn.net/wk3510/article/details/127819217

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯