SpringAOP学习中

2018-11-21  本文已影响0人  取名废同学

springAOP面向切面编程,非编程语言,是编程范式,只能解决特定问题,是OOP的补充而非替代。

初衷:解决代码重复性问题;
关注点分离(水平分离:分展示层、服务层、持久层;垂直分离:按功能模块;切面分离:分离功能性需求和非功能性需求)

使用AOP的好处:
集中处理某一关注点/横切逻辑
方便添加/删除关注点
侵入性少,增强代码可读性与可维护性

AOP的应用场景:
权限控制、缓存控制、事务控制、审计日志、性能监控、分布式追踪、异常处理。

支持AOP的编程语言:
JAVA .net python c/c++... ruby...

例如:举一个场景的例子,添加或删除的操作必须由管理员完成,这是两个方法,用普通方法,是添加和删除方法中,要先加【判断是否为管理员的代码】,运用AOP的方式,则是把【判断是管理员】的代码切出来

SpringAOP的使用方式
1、XML配置
2、注解方式在java文件中
@Aspect:在类前,用于说明该类是切面的配置的类
@Pointcut:描述在哪些类/哪些方法植入你的代码
Advice:你想在以上方法的什么时候进行植入,之前?之后?
@Component:让这个类给spring托管

一、切面表达式Pointcut expression:
designators:指示器,通过什么方式去匹配想要的java的类的方法


image.png

wildcards:通配符 (*:任意数量; +:匹配指定类及子类; 。。:匹配任意数的子包或参数
operators:运算符,组合(&&;||;!)

(一)designators:指示器
1、within表达式:限定在哪个类或哪个包


image.png

2、对象匹配:


image.png

常默认this和target一样

3、参数匹配:
两种方法:定义execution方法(要返回值啥的,麻烦)和args方法


4、注解匹配:4个,一个是匹配方法级别,2个匹配类级别,一个匹配参数级别


image.png

1匹配注解级别,2、3匹配类级别,一般默认相同;4匹配方法级别

5、execution表达式:



修饰符pattern
返回值类型pattern
描述包名
描述方法名(描述参数)
匹配方法抛出异常
(1 3 5可省略)

二、Advice注解
@Before:前置通知,方法前执行
@After(finally):后置通知,方法执行完之后
@AfterReturning:返回通知,成功执行之后,有返回值
@AfterThrowing:异常通知,抛出异常之后
@Around:环绕通知,万能注解


image.png

SpringAOP实现原理:
aop织入时机:
1、编译期(AspectJ)
2、类加载时(AspectJ 5+)
3、运行时(Spring AOP)

运行时织入:代理对象
【代理:
静态代理:
动态代理:基于接口代理/基于继承代理】

设计模式:代理模式、责任链模式
一、代理模式(静态代理)
委托类和代理类实现同一接口,并写同一个方法,代理类中有委托类的一个实例,在其方法中,还是用委托类的实例来完成这个方法。


image.png

缺点:重复方法;

二、动态代理:
两类实现:基于接口/基于继承代理
两类实现代表:JDK代理与Cglib代理
1、JDK代理:
通过类java.lang.reflect.Proxy动态生成代理类
代理类需要实现InvocationHandler接口(接口有invoke方法,代理类中还需引用委托类对象)
jdk代理只能基于接口进行动态代理
优点:如果有多个方法,也无需在代理类中重写,只需在接口中写
2、JDK代理源码解析


image.png

方法,去调用其他3个方法,
最后生成字节码用java反射生成实例

3、Cglib动态代理:通过继承的方式来实现代理


image.png

4、spring对两种实现的选择:
目标对象实现接口,默认采用JDK代理;
目标对象无实现接口,采用cglib代理;
目标对象实现了接口但强制cglib代理,则cglib


二、责任链模式:
多个AOP链式调用 ,


1、抽象类Handler中有HanlerProcess()抽象方法,需要实现类实现,同时实现类又组合了Handler,通过这种successor的判断来实现链式调用


image.png

successor用于判断接下来还有没有人去处理。



对象存在,则接下来调用链式的execute()

2、创建多个继承Hanler抽象类的类,然后在各自的handlerProcessor()执行各自的业务逻辑

2、客户端中设置多个类的调用关系,只调用第一个的execute()
handlerA.setSuccessor(handlerB);
handlerB.setSuccessor(handlerC);
hanlerA.execute()

所有代码:
Hanler抽象类:

public abstract class Handler {
     private Handler successor;

     public Handler getSuccessor() {
          return successor;
     }

     public void setSuccessor(Handler successor) {
          this.successor = successor;
     }

     public void execute(){
          handlerProcess();
          if(successor!=null){
               successor.execute();
          }
     }

     protected  abstract  void handlerProcess();
}

客户端Client类,其中有三个内部静态类ABC继承hanler类

public class Client {
    static class HandlerA extends Handler{
        @Override
        protected void handlerProcess() {
            System.out.println("hanler by a");
        }
    }

    static class HandlerB extends Handler{
        @Override
        protected void handlerProcess() {
            System.out.println("hanler by b");
        }
    }

    static class HandlerC extends Handler{
        @Override
        protected void handlerProcess() {
            System.out.println("hanler by c");
        }
    }

    public static void main(String[] args) {
        Handler handlerA = new HandlerA();
        Handler handlerB = new HandlerB();
        Handler handlerC = new HandlerC();

        handlerA.setSuccessor(handlerB);
        handlerB.setSuccessor(handlerC);
        handlerA.execute();
    }
}

缺点:在于必须手动把链式调用的链式关系写出来,比较麻烦。
所以进行改进,将上面那块进行封装成一个类

Chain中有一个内部List<handler>,然后把所有的handler存进去,内部实现游标的跳转,不断调用下一个。

ChainHandler:

public abstract class ChainHandler {

    public void execute(Chain chain){
        handleProcess();
        chain.proceed();//调用下一个游标
    }
    protected abstract void handleProcess();
}

Chain:

import java.util.List;

public class Chain {
    private List<ChainHandler> handlers;
    private int index=0;
    public Chain(List<ChainHandler> handlers){
        this.handlers=handlers;
    }
    public void proceed(){
        if(index>=handlers.size()){
            return;
        }
        handlers.get(index++).execute(this);
    }
}

ChainClient:

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;

public class ChainClient {
    static class ChainHandlerA extends ChainHandler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by chain a");
        }
    }
    static class ChainHandlerB extends ChainHandler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by chain b");
        }
    }
    static class ChainHandlerC extends ChainHandler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by chain c");
        }
    }
    public static void main(String[] args){
        List<ChainHandler> handlers= Arrays.asList(
                new ChainHandlerA(),
                new ChainHandlerB(),
                new ChainHandlerC()
        );
        Chain chain=new Chain(handlers);
        chain.proceed();
    }
}

springAOP也是使用这种Chain方式,用游标的方式。

使用springAOP注意事项:
1、不把重要的业务逻辑放到AOP中处理,容易被忽略,应该放比较通用的业务
2、无法拦截static、final、private方法
3、无法拦截内部方法调用

上一篇下一篇

猜你喜欢

热点阅读