AOP简略介绍

名称: 面向切面编程
作用: 升高零碎中代码的耦合性,并且在不扭转原有代码的条件下对原有的办法进行性能的扩大.
公式: AOP = 切入点表达式 + 告诉办法

告诉类型

1.前置告诉 指标办法执行之前执行
2.后置告诉 指标办法执行之后执行
3.异样告诉 指标办法执行过程中抛出异样时执行
4.最终告诉 无论什么时候都要执行的告诉

特点: 上述的四大告诉类型 不能干涉指标办法是否执行.个别用来做程序运行状态的记录.【监控】

5.盘绕告诉 在指标办法执行前后都要执行的告诉办法 该办法能够控制目标办法是否运行.joinPoint.proceed(); 性能作为弱小的.

切入点表达式

切入点表达式就是一个程序是否进入告诉的一个判断(IF)。
作用:当程序运行过程中,满足了切入点表达式时才回去执行告诉办法,实现业务的扩大。
品种(写法):
1.bean(bean的名称 bean的ID) 只能拦挡具体的某个bean对象,只能匹配一个对象。
例如:bean("itemServiceImpl")
2.within(包名.类名) within("com.jt.service.*")示意能够匹配多个对象。
3.execution(返回值类型 包名.类名.办法名(参数列表))最为弱小的用法
例如 : execution( com.jt.service...*(..))返回值类型任意 com.jt.service包下的所有的类的所有的办法都会被拦挡.
4.@annotation(包名.注解名称) 依照注解匹配.

AOP入门案例

package com.jt.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;@Aspect //我是一个AOP切面类@Component  //将类交给spring容器治理public class CacheAOP {    //公式: 切入点表达式+告诉办法    /**     * 对于切入点表达式的应用阐明     *  粗粒度     *      1.bean(bean的id)     一个类     *      2.within(包名.类名)   多个类     *  细粒度     *      1.     */    //@Pointcut("bean(itemCatSercviceImpl)")    //   .*示意以后包上面的一级目录。    //   ..*示意以后包上面的多级目录    /*@Pointcut("within(com.jt.service..*)")    public void pointCut(){        //定义切入点表达式, 为了占位    }*/    //定义前置告诉,与切入点进行绑定 @Before("pointCut()")    //或者用更简略的办法:不必定义切入点办法pointCut(),    // 间接绑定bean:@before(“bean(itemCatSercviceImpl)”)    /*两者的区别:    *       1.@Before("pointCut()")示意切入点表达式的援用,实用于多个告诉同用切入点的状况    *       2.@before(“bean(itemCatSercviceImpl)”)实用于单个告诉,不须要复用的    * */    /**@Before("pointCut()")    public void before(){        System.out.println("我是前置告诉");    }    @AfterReturning("pointCut()")    public void afterreturn(){        System.out.println("我是后置告诉");    }*/    @Before("pointCut()")    public void before(JoinPoint joinPoint){        //JoinPoint:连接点办法        //getStaticPart()代表连接点的办法签名        //getName()办法的名称        String methodName = joinPoint.getSignature().getName();        //getDeclaringTypeName()获取类的门路全名com.jt.service.ItemCatSercviceImpl        String className = joinPoint.getSignature().getDeclaringTypeName();        System.out.println(className+"."+methodName);        //getTarget()代表指标对象        //getTarget().getClass()获取指标对象的类型        Class<?> targetClass = joinPoint.getTarget().getClass();        //获取对象的参数        Object[] args = joinPoint.getArgs();        //获取执行工夫        Long startTime= System.currentTimeMillis();        System.out.println("指标办法类型"+targetClass);        System.out.println("执行工夫:"+startTime+"毫秒");    }    /**     * 盘绕告诉阐明     *  注意事项:     *      ProceedingJoinPoint只能用在盘绕告诉里     *      1.盘绕告诉必须增加参数ProceedingJoinPoint     *      2.ProceedingJoinPoint只能盘绕告诉应用     *      3.ProceedingJoinPoint如果当做参数则必须位于参数的第一位     */    @Around("pointCut()")    public Object around(ProceedingJoinPoint joinPoint){        System.out.println("盘绕告诉开始!!!");        Object result=null;        try {            result=joinPoint.proceed();//执行下一个告诉或者指标办法        } catch (Throwable throwable) {            throwable.printStackTrace();        }        System.out.println("盘绕告诉完结!!!");        return result;    }}

对于AOP实现Redis

自定义缓存注解

问题:如何管制,哪些办法须要应用缓存?【cacheFind()查询方法】
解决方案:采纳自定义注解的模式进行定义,如果办法执行须要应用缓存,则标识注解即可。
对于注解的阐明:
1.注解名称:cacheFind
2.属性参数:

1.key:应该由用户本人手动增加,个别增加业务名称之后动静拼接造成惟一的key。2.seconds:用户能够指定数据的超时工夫。

//自定义一个注解@Target(ElementType.METHOD)//该注解只对办法无效@Retention(RetentionPolicy.RUNTIME)//运行期无效public @interface CacheFind {    String preKey();//用户标识key的前缀。 int seconds() default 0;//如果用户不写示意不须要超时,如果写了就以用户为准。}

编辑CacheAOP

package com.jt.aop;import com.jt.anno.CacheFind;import com.jt.util.ObjectMapperUtil;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import redis.clients.jedis.Jedis;import java.util.Arrays;@Aspect //我是一个AOP切面类@Component //将类交给spring容器治理public class CacheAOP {    @Autowired private Jedis jedis;    /**     AOP实现Redis缓存 * 切面=切入点+告诉办法 * 注解相干+盘绕告诉        控制目标办法是否执行 * * 难点: *      1.获取注解的对象,将注解作为参数传过来 *      2.动静生成key  prekey+用户参数数组 *      3.如何获取办法的返回值类型 */ @Around("@annotation(cacheFind)")    public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){        System.out.println("注解拦挡失效");        Object result=null;        try {            //拼接redis存储数据的key Object[] args=joinPoint.getArgs();            String key=cacheFind.preKey()+"::"+ Arrays.toString(args);            //查问redis 之后判断是否有数据 if(jedis.exists(key)){                //示意redis中有数据,无需执行指标办法 String json = jedis.get(key);                //动静获取办法的返回值类型  向上转型  向下转型 MethodSignature methodSignature=(MethodSignature)joinPoint .getSignature();                //示意客户端传来什么类型就返回什么类型 Class returnType = methodSignature.getReturnType();                //须要将json串转化为对象 result=ObjectMapperUtil.toObj(json, returnType);                System.out.println("redis缓存中的数据");            }else{                //示意数据不存在,须要在数据库中查问 result=joinPoint.proceed();//执行指标办法和告诉 //将查问的数据存储到redis缓存中 String json = ObjectMapperUtil.toJson(result);                //判断是否须要超时工夫 if(cacheFind.seconds()>0){                    jedis.setex(key, cacheFind.seconds(), json);                }else{                    jedis.set(key, json);                }                System.out.println("aop执行指标办法查询数据库");            }        } catch (Throwable throwable) {            throwable.printStackTrace();        }        return result;    }}