大数据WEB阶段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;
        } 
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值