简单的谈一谈AOP(面向切面编程)

时光如梭,转眼之间,春招已然结束,秋招正在赶来,又到了技术布道的时候了。。
今天简单的聊一聊AOP(Aspect Oriented Programming)

起因

项目中需要查看一些方法前后的运行时间,以便合理的推测出代码是否能够扛得住XXQPS的访问。要是每个方法前后都写一个时间减法,那可真是个累活了,于是AOP思想出来了。。

通过一个条件来匹配想要拦截的代码,这个条件在AOP中就是PointCut(切点)
切点搞定之后,只需要再做一个切面(即定义拦截后的操作)就行了。

简单的实现AOP

假设现在有一个需求:

interface Passing{
void Time_Consume(String name);
}

在这个接口前面和后面都打印出特定的字符串

方法一:写死代码

interface Passing{
    void Time_Consume(String name);
}
class PassingImpl implements Passing{
     public void Time_Consume(String name){
         before();
         System.out.println("the time:"+name);
         after();
     }
     private void before(){
         System.out.println("Before");
     }
     private void after(){
         System.out.println("After");
     }
}
public class Hello {
    public static void main(String []args){
//        System.out.println("Hello world");
        new PassingImpl().Time_Consume("Now");
    }
}

如果只有一个方法那还好说,但是万一每个方法都要有这个需求,那工作量可就完蛋了,所以AOP来了。
一般可以有以下三种解决方案:
* 静态代理
* JDK动态代理
* CGLIB动态代理

静态代理

interface Passing{
    void Time_Consume(String name);
}
class PassingImpl implements Passing{
     public void Time_Consume(String name){
         before();
         System.out.println("the time:"+name);
         after();
     }
     private void before(){
         System.out.println("Before");
     }
     private void after(){
         System.out.println("After");
     }
}
class PassingProxy implements Passing{
     private PassingImpl passingImpl;
     public PassingProxy(PassingImpl passingImpl){
         this.passingImpl=passingImpl;
     }
     @Override
     public void Time_Consume(String name){
         before();
         passingImpl.Time_Consume(name);
         after();
     }
     private void before(){
         System.out.println("Before");
     }
     private void after(){
         System.out.println("After");
     }
}
public class Hello {
    public static void main(String []args){
//        System.out.println("Hello world");
//        new PassingImpl().Time_Consume("Now");
        Passing passingProxy=new PassingProxy(new PassingImpl());
        passingProxy.Time_Consume("Now");
    }
}

静态代理看起来还是不错的,但是如果我想多代理几个其他的,那还得为其他的几个量身定做几个,这重复劳动要不得,所以就有了接下来的JDK动态代理。

JDK动态代理

class JDKDynamicProxy implements InvocationHandler{
    private Object target;
    public JDKDynamicProxy(Object target){
        this.target=target;
    }
    public <T> T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this::invoke);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result=method.invoke(target,args);
        after();
        return result;
    }
    private void before(){
        System.out.println("Before");
    }
    private void after(){
        System.out.println("After");
    }
}
public class Hello {
    public static void main(String []args){
//        System.out.println("Hello world");
//        new PassingImpl().Time_Consume("Now");
//        Passing passingProxy=new PassingProxy(new PassingImpl());
//        passingProxy.Time_Consume("Now");
        Passing passing=new JDKDynamicProxy(new PassingImpl()).getProxy();
        passing.Time_Consume("Now");
    }
}

如此这般,所有的代理类都能够合并到动态代理类中,还是得感谢泛型,但是这样做有一个问题:JDK的动态代理只能够提供有代理接口的,不能代理没有接口的类,这下麻烦大了,万一项目中就是需要代理没有接口的类该咋办呢。CGLib动态代理!

CGLib动态代理

使用开源的CGLiB类库可以代理没有接口的类,这样就完美解决了上述问题,该代理以后有时间再详细研究研究

Spring AOP:

AOP框架可以理解为一个拦截器框架,只需要拦截特定的方法即可,这个时候切面(AOP的实现方式) 就是AOP的核心,即给出如何拦截的方式,说白了就是通过切面,将拦截匹配的条件组合在一起,然后 将这个切面配置到ProxyFactory中,从而生成代理。

最后附上一张AOP思维导图
这里写图片描述

小结
感谢本书《架构探险》,AOP确实值得好好的研究研究。

猜你喜欢

转载自blog.csdn.net/mikeoperfect/article/details/80616290