大数据WEB阶段Spring框架 AOP面向切面编程(二)

标签: 大数据  spring  框架  aop

Spring AOP面向切面编程(二)

一、切入点的execution表达式

  1. execution的表达形式: execution(修饰符? 返回值类型 所在包类? 方法名(参数列表) 异常?)

    1. ?表示可有可无
       execution(public * *(..))
      工程中所有的public方法
      execution(* set*(..))
      工程中所有方法名以set开头的方法
      execution(* com.xyz.service.AccountService.*(..))
      com.xyz.service.AccountService类下面的所有方法

    execution(* com.xyz.service..(..))

    com.xyz.service包下所有类的所有方法

    execution(* com.xyz.service...(..))
    com.xyz.service包下及其子包下所有类的所有方法
    execution(* com.xyz..service..(..))
    报名以com.xyz开头的所有子包一直子到service下的所有类的所有方法
    举例:com.xyz.a.b.service com.xyz.a.service com.xyz.a.b.c.service 会满足上面的条件

二、五大通知的具体实现

  1. 环绕通知 around
    1. 5个中最强大的通知,唯一一个能在通知中控制目标方法是否执行的通知
  2. 前置通知
    1. 配置文件配置
  3. 后置通知
    1. 配置文件配置
  4. 异常通知
    1. 异常通知可以控制出现异常后事务回滚 , 和记录日志
    2. 配置文件配置
    3. 注意: JoinPoint参数必须放在第一位
  5. 最终通知
    1. 不管是么情况都会执行

三、AOP注解

  1. 在配置文件中把aop注解开关打开
  2. 通过注解配置切面类
  3. 通过注解配置通知方法
    1. 前置通知
    2. 后置通知
    3. 环绕通知
    4. 异常通知
    5. 最终通知

四、通过注解生成切入点表达式的引用

  1. 创建一个空方法
    1. 使用@Pointcut注解生成一个切入点的引用
    2. 使用

五、环绕嵌套问题

六、自定义注解

  1. 声明一个注解
  2. 使用
  3. 判断是否有注解

七、各种示例

  1. 异常

    代码结构如图所示
            PersonServlet
                PersonService
                    PersonDao
    用异常通知捕获servlet的所有的方法抛出的异常:
    目标对象所在的类            cn.tedu.big1601.servlet.PersonServlet
    抛出异常所在的方法           save()
    抛出异常的名称              XxxException
    异常信息                    message
    
    意义:
    异常处理类和业务逻辑类完全松耦合。
    时刻捕获生产生产环境中所有的错误,实时监控该系统,异常收集。
    
    @Component
    @Aspect
    public class ExceptionAspect {
        @AfterThrowing(value = "execution(* com.tj..*(..))" ,throwing = "throwable" )
        public void after(JoinPoint  jp , Throwable throwable){
            System.out.println("异常发生在:"+jp.getTarget().getClass());
            System.out.println(jp.getSignature().getName()+"()发生了异常!");
            System.out.println("发生异常类型:"+throwable.getClass());
            System.out.println("异常信息:"+throwable.getMessage());
        }
    }
    
  2. 统计方法执行时间

    计算servlet的各个类的各个方法的执行时间
    1.类的名称
    2.方法的名称           
    3.执行的时间
    控制台输出
    
    意义:用来监控程序的性能问题      
    
    @Component
    @Aspect
    public class RuntimeAspect {
    
        @Around("execution(* com.tj..*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            Long begin = System.currentTimeMillis();
            Object result = pjp.proceed();
            Long end = System.currentTimeMillis();
            System.out.println(pjp.getTarget().getClass()+"类"+pjp.getSignature().getName()+"方法执行了"+ (end - begin)+"毫秒!");
            return result;
        }
    }
    
  3. 事务控制

    当方法上有事务的注解,该方法就有事务。
                    写一个切面来完成
    
    事务控制类       
    public class TxManage {
        /**
         * 开启事务
         * */
        public static void stattx(){
            System.out.println("开启了事务");
        }
        /**
         * 提交事务
         * */
        public  static void commitTx(){
            System.out.println("提交事务");
        }
        /**
         * 回滚事务
         * */
        public static void rollback(){
            System.out.println("事务回滚");
        }
    }
    
    自定义事务注解
    @Target(value = { ElementType.METHOD })
    @Retention(value = RetentionPolicy.RUNTIME)
    public @interface TxAnnotation {
        String value() default "";
    
    }
    
    给需要事务控制的地方添加注解
    @Component
    public class PersonServiceImpl implements PersonService{
        @Autowired
        private PersonDao dao;
    
        @TxAnnotation
        @Cacheable("add")
        @Override
        public void savePerson(Person person) {
            dao.savePerson(person);
        }
    
        @TxAnnotation
        @Cacheable("get")
        @Override
        public Person getPerson(int id) {
            Person person = dao.getPerson(id);
            return person;
        }
    
        @TxAnnotation
        @Cacheable("del")
        @Override
        public void delPerson(int id) {
            dao.delPerson(id);
        }
    
    }
    
    事务控制切面
    @Component
    @Aspect
    public class TxAspect {
    
        @Around(value = "execution(* com.tj..*(..)) && @annotation(ann)")
        public Object around(ProceedingJoinPoint pjp ,TxAnnotation ann  ) throws Throwable{
            Object result = null;
            try{
                TxManage.stattx();
                result = pjp.proceed();
                TxManage.commitTx();
            }catch(Exception e){
                TxManage.rollback();
            }
            return result; 
        }
    }
    
  4. 权限控制

    说明:每个方法上添加能够执行该方法的注解@PrivilegeInfo  并且要指明
    PrivilegeInfo(name=”add”)   那么将来这个方法只能执行还有add权限的方法
    
    自定义权限控制注解
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PrivilegeInfo {
        String value() ;
    }
    
    给需要控制权限的地方添加权限控制注解
    @Component
    public class PersonServlet {
        @Autowired
        private PersonService ps;
    
        /**
         * 保存用户信息
         * */
        @PrivilegeInfo("add")
        public void  savePerson(Person person){
    //      int  i  = 1/0;
            ps.savePerson(person);
        }
        /**
         * 获取用户信息
         * */
        @PrivilegeInfo("get")
        public Person getPerson(int id){
            Person person = ps.getPerson(id);
            return person ; 
        }
        /**
         * 删除用户信息
         * */
        @PrivilegeInfo("del")
        public void delPerson(int id  ){
            ps.delPerson(id);
        }
    }
    
    权限控制切面类
    
    @Component
    @Aspect
    public class PrivilegInfoAspect {
        //当前用户的权限
        List<String> list =Arrays.asList("add" , "get");
        @Around("execution(* com.tj..*(..)) && @annotation(ann)")
        public Object around(ProceedingJoinPoint pjp , PrivilegeInfo ann) throws Throwable{
    
            String value = ann.value();
            Object result = null;
            if(list.contains(value)){
                System.out.println("尊敬的飞秋会员你好!");
                result = pjp.proceed();
            }else{
                System.out.println("你没有这个权限 ,滚");
            }
            return result;
        }
    
    }
    
  5. 数据缓存

    缓存需求:1.savePerson的时候需要往数据库里保存一份然后再往内存(Map)中保存一份 
    2.getPerson的时候先从Map中获取 如果有则返回则不用执行目标方法,如果内存中没有则执行目标方法从数据库取
    3.如果第一次调用getPerson内存中没有的话 执行目标方法从数据库取 取出来后同时把获取到的Person对象保存到内存中,以便后续获取时直接从内存中取
    
    自定义 缓存控制注解
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Cacheable {
        String value();
    }
    
    给需要缓存的地方添加注解
    @Component
    public class PersonServiceImpl implements PersonService{
        @Autowired
        private PersonDao dao;
    
        @TxAnnotation
        @Cacheable("add")
        @Override
        public void savePerson(Person person) {
            dao.savePerson(person);
        }
    
        @TxAnnotation
        @Cacheable("get")
        @Override
        public Person getPerson(int id) {
            Person person = dao.getPerson(id);
            return person;
        }
    
        @TxAnnotation
        @Cacheable("del")
        @Override
        public void delPerson(int id) {
            dao.delPerson(id);
        }
    
    }
    
    缓存控制切面类
    @Component
    @Aspect
    public class CacheableAspect {
        //缓存
        Map<Integer , Person> map =  new HashMap<Integer,Person>();
    
        @Around("execution(* com.tj..*(..))&& @annotation(ann)")
        public Object befer(ProceedingJoinPoint jp  , Cacheable ann) throws Throwable{
            Object result = null;
            String v = ann.value();
            if(v.equals("add")){
                Person  person = (Person) jp.getArgs()[0];
                int id = person.getId();
                if(map.containsKey(id)){
                    System.out.println("该用户已存在");
                }else{
                    System.out.println("存入 缓存");
                    map.put(id, person);
                    result = jp.proceed();
                }
            }else if(v.equals("get")){
                int id = (Integer) jp.getArgs()[0];
                if(map.containsKey(id)){
                    System.out.println("从缓存中获取");
                    result  = map.get(id);
                }else{
                    result = jp.proceed();
                    Person person =  (Person) result;
                    map.put(person.getId(), person);
                }
            }
            return result;
        } 
    }
    
版权声明:本文为chou_out_man原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chou_out_man/article/details/78876161

智能推荐

zabbix远程命令执行

zabbix可以通过远程发送执行命令或脚本来对部分的服务求故障进行修复 zabbix客户端配置 设置zabbix客户端用户的sudo权限 在客户端的配置文件zabbix_agentd.conf中添加下面语句,开启对远程命令的支持,添加完成后重启下服务 输入下面命令手动检测,有内容则表示远程命令可用,否则提示remote commands are not enable 在119服目录/data下添加...

机器学习中K-means聚类算法的原理及实现(Python)

背景知识 K-means聚类算法是一种流行于数据挖掘领域的无监督学习算法。K-means聚类算法的目的是:把已知的 n个点划分到k个聚类中,使得每个点都属于离它最近的点(聚类中心)对应的聚类。 在完成该算法的过程中,找到k个聚类中心是关键。 算法介绍 我们先介绍几个基本概念: 簇:数据点的集合,每一个簇中的对象是相似的。 质心:簇中所有点的中心(由计算所有点坐标的均值可得)。 比如在这幅图中,我们...

接口回调基础理解

接口回调听起来好像很厉害的样子,但其实只要能够搞清楚代码的执行过程,多看几遍,并且认真思考,再加上勤奋的练习,熟练掌握简单的接口回调并不是难题,接下来,我会用一个简单的例子,来带大家一起分析代码的执行过程,以及这样写的好处,以及这样写的思路。 我们知道recyclerView是没有自带点击事件的,所以这里我们就拿给recyclerView添加点击事件为例。 ok 我们做好了一个简单的recycer...

Mac下的myeclipse安装

1.首先要安装jdk跟jre 2.安装过程中可能会遇到您需要安装旧 Java SE 6 运行环境才能打开此 Java 应用程序的提示     解决办法就是安装ava for os x 2015-001.,这里不要点系统给你提示的界面,根本没法下载 我上传的链接,可以直接下载:链接: https://pan.baidu.com/s/1qYbT6os 密码: x...

30分钟实战树莓派连接到微软云Azure IoT Hub并将数据可视化

更多内容,关注公众号: 树莓派是很多动手达人必备的小玩具,本节内容,让我们拿出树莓派,在30分钟内,将树莓派连接到微软云Azure的IoT Hub,然后将温湿度曲线可视化。 本实战完整视频: 树莓派连接到Azure IoT Hub 并用时序见解展示数据 本节内容中,树莓派发送的数据是模拟出来的,并没有真实的连接到传感器,您可以选购不同的传感器来采集真实的环境信息。 Azure IoT Hub 为我...

猜你喜欢

spring cloud gateway 整合ribbon、nacos discovery实现负载均衡源码简析

1 spring cloud gateway 负载均衡入口 spring cloud gateway 使用 LoadBalancerClientFilter 来实现载均衡的功能,该过滤器通过LoadBalancerClient.choose(ServerWebExchange exchange)方法来获取目标实例。 LoadBalancerClient 为spring-cloud-commons包...

VUE快速搭建项目

作为一个前端小辣鸡 今天在网上找到了 一个 快速 无脑式搭建vue项目的方式 分享一下 我们采用图形界面创建项目。通过 vue ui 命令启动 vue cli service 后,访问 http://localhost:8000/project/create 可以直接进入项目创建流程。 步骤中有些地方值得一提 详情:包管理器指定 npm,后续在npm 配置文件(.npmrc)中可手动指定国内镜像源...

2017-8-10 Struts2学习笔记二

一、web.xml文件的编写 1. 由于struts2是用过滤器拦截请求的,所以需要在web.xml文件中配置一个过滤器。 2. 这个过滤器的名字叫StrutsPrepareAndExecuteFilter,中文名曰struts准备和执行过滤器,就是这个过滤器拦截我们在地址栏的请求。 3. 查找这个过滤器,将它的全路径写在filter-class标签中,eclipse可以使用Shift+Ctrl+...

Windows Terminal配置Git

文章目录 Windows Terminal配置Git 效果 下载和安装 配置Windows Terminal 配置其它命令行 Windows Terminal配置Git 效果 先上效果图: 下载和安装 Windows Terminal是微软开发的面向命令行用户的全新,现代,功能丰富,高效的终端应用程序。 它包括Windows命令行社区最常请求的许多功能,包括对选项卡,富文本,全球化,可配置性,主题...

CW MCU v11.1学习笔记1

说明:通过处理器专家创建芯片为MC9S08DZ60的工程,按键控制LED 一、CW11.1软件界面布局 1、双击桌面图标,打开软件,设置工作空间 软件主界面 调试界面 处理器专家界面 有时经常调整(删除)面板布局,如果想恢复布局,可在Window工具栏下的Reset Perspective选项来复位面板布局 二、新建工程 1、在C/C++模式下,在Commander面板下点击New MCU pro...