Spring in Anction:Spring AOP 小记

1.什么是AOP(面向切面编程)

AOP

不扯那些概念的东西,简单说来AOP是OOP的一个补充,AOP可以在程序运行期追加一些公用的功能,比如权限判断,日志记录,这些功能都是项目需要的,但是又不能每个地方都调用,这样无疑增加了代码的复杂度和工作量,我们可以将这些分散在系统中的公用代码集中于一个地方并通过aop技术应用于系统各个地方。

2. AOP术语

  • 切点:我们需要插入这些公用功能的点?比如哪些类?哪些方法?等等(何处调用)
  • 切面:这些公用功能代码(调用什么)
  • 通知:在什么时候调用?

3.通知分类

  • 前置通知(Before):在目标方法调用前调用
  • 后置通知(After):在目标方法调用后调用
  • 返回通知(AfterReturning):在目标方法成功执行后调用
  • 异常通知(AfterThrowing):在目标方法执行失败抛异常后调用
  • 环绕通知(Around):将目标方法包裹,由你决定什么时候调用(最强大,最常用)

3.Spring AOP

Spring 通过生成代理类将目标对象包裹从而实现AOP,调用者调用目标方法时,其实是在调用代理类,再由代理类
调用目标方法,从而控制对目标方法的调用,Spring只支持最细方法级别的连接点,如果需要实现更细粒度的控制
则需要借助专业的AOP框架AspectJ,可以控制字段,构造方法等更细的东西,不过需要学习新的语法。

AOP

4.Spring 切点表达式

可以通过这些表达式配置切点

AOP

上面是Spring支持的AspectJ 切点表达式。除execution是增加切点范围的外,其他都是用于缩小范围

5.编写切点

AOP

6.编写切面

用注解@Aspect表示一个切面,注解用于类上

@Aspect //表示是切面
@Component //Bean注入Spring
@Order(1)//优先执行该切面
public class TicketLoginAspect {
    @Autowired
    private HttpServletRequest request;

    /**
     * 切点
     */
       //表示作用于TicketLogin注解
    @Pointcut("@annotation(com.cnct.webchat.common.annotation.TicketLogin)")
    public void loginPointCut() {
        //扩展作用范围,不用在每个@Around后写很长的表达式了,只需写方法名即可,像下面
    }

    @Around("loginPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
    }
  }

写完切面后要开启Spring aop自动代理才能生效,如果使用JavaConfig的话,在配置类上使用
@EnableAspectJ-AutoProxy即可,如果用XML配置则加入

7.通过注解为目标类增加新功能(方法)

既然AOP通过代理实现,那么就可以为目标对象增加新的代理方法。

@Aspect //定义切面
@Component
public class TestAop{
  @DeclareParents(value = "com.lyq3.NewFunctionInterface+",
                  defaultImpl = NewFunctionImpl.class
  )
  public static Abc abc;
}
  • value 指定那种类型的Bean要引入,(后面的“+”号表示所有的子类型而不是本身)
  • defaultImpl 指定引入功能的实现类
  • @DeclareParents 所标注的静态属性指明要引入的接口,也就是要为Abc接口增加新功能

8.注意:踩坑记

@Aspect
@Component
@Order(2)//登录注解执行后执行该注解
public class HandleRecordAspect {
    @Autowired
    private HandleRecordMapper handleRecordMapper;
    @Autowired
    private HttpSession session;
    /**
     * 切点
     */
    @Pointcut("@annotation(com.cnct.webchat.common.annotation.HandleRecord)")
    public void handlePointCut() {

    }

    @Around("handlePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //先执行方法
        Object result = point.proceed();
        //访问目标方法的参数:
        Object[] args = point.getArgs();

        Signature sig = point.getSignature();
        MethodSignature msig = null;
        msig = (MethodSignature) sig;
        Method method = msig.getMethod();
//        String methodName = msig.getName();//方法名
        HandleRecord handleRecord = method.getAnnotation(HandleRecord.class);//获取注解
        //操作标识(增?删?改?)
        int handle_status = handleRecord.handle_status();
        String remark = handleRecord.value();
      }
    }

上面的代码是我在项目中实现一个存操作纪录的部分代码,咋一看没毛病。@HandleRecord这个自定义注解在Controller层能用,我放到Service层的时候(service有接口和接口实现,注解放实现类方法上)

  HandleRecord handleRecord = method.getAnnotation(HandleRecord.class);

这句代码是获取不到注解的,也就是说 handleRecord = null;

原因是AOP采用的jdk代理,MethodSignature 转型之后,会丢失子类的方法注解,所以得先获取实现类的方法

修改下代码,就能用了:

//先执行方法
        Object result = point.proceed();
        //访问目标方法的参数:
        Object[] args = point.getArgs();

        Signature sig = point.getSignature();
        MethodSignature msig = null;
        msig = (MethodSignature) sig;
        Method method = msig.getMethod();
        //MethodSignature 转型之后,会丢失子类的方法注解,所以得先获取实现类的方法
        //============================================
        Method soruceMethod = point.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());
        //=============================================
        HandleRecord handleRecord = soruceMethod.getAnnotation(HandleRecord.class);//获取注解
        //操作标识(增?删?改?)
        int handle_status = handleRecord.handle_status();
        String remark = handleRecord.value();

详情查看Spring in Action 第四版 第四章

本文作者: 小小牛
本文链接: http://blog.lyq3.com/2017/08/22/Spring_in_Action/Spring-AOP/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值