AOP-切面编程理解

切面编程保留原有结构,不破坏系统,插入自定义需求。静态代理通过装饰器模式实现,适用于单一扩展,但可能导致代码翻倍。动态代理克服了静态代理的一些限制,能代理接口,但需接口存在。AOP提供了一种在生命周期内注入特定操作的框架,用于扩展方法和流程控制。
摘要由CSDN通过智能技术生成

AOP

什么是切面

把皮肤切开,塞一本经书进去,然后缝合。

维护原有结构,在不破坏结构的条件下,插入自定义的东西,这就是切面。

能做写什么

上面塞经书的,是一个和尚,因为大乘真经被隔绝的很严重,他用这种办法带出了经书。

还是那个熟悉的面孔,一切还是熟悉的模样,只是,夹带了一些私货,也就是我们的目的。

乔装打扮,伪造学历…

本质上仍然是那个谁,不过的确能够达成了一些额外的需求。

这是原本所不具备的,也正是我们所需要的。

有什么不同

AOP,就是保留原有的滋味,同时,增加额外的信息或操作。

静态代理

首先明确一点:保留固有特征情况下,增加额外的需求。

单纯的从这个目的出发,这样就可以实现

Service

public class Service {
    public void service(String name){
        System.out.println("service with name : " + name);
    }
}

ServiceProxy

public class ServiceProxy {
    private Service service;
    public  ServiceProxy(Service service){
        this.service = service;
    }
    public void before(){
        System.out.println("before");
    }
    public  void after(){
        System.out.println("after");
    }
    public void service(String name){
        before();
        service.service(name);
        after();
    }
}

装饰器模式,代理模式或者什么其他的东西,你都可以称呼。

不理会名头,简单来说,调用前后做了些动作,如是而已,目的的确达成了。

不过有意思的是,装饰器模式或其他类似的东西,有自成一派的需求:

  • 它可能需要,或者不需要,或者不同需要
  • 重要的是它本身,同时附带其他东西

对于这些需求,采用这种模式,装饰器更贴近一些。

朴实一点来说,如果只是一个东西做扩展,想玩出花样,装饰者设计模式无可厚非。

一整箱的衣服,只为一位女士各种需求,的确需要装饰。

不过,这种方式,有一些弊病:

  • 装饰总是很多,原体唯一一个(量身定做)

想象一下在军队中,单纯的只需要一身铠甲,不论合身与否,只在乎坚韧。

但是又成千上万的军人。

在这种场景下,量身定做,是否不太现实。

用程序的角度称述:每一个原型对象,总需要另一个代理对象来装饰。

全部装饰,业务逻辑之外的对象代码,那可就都得翻番了。

动态代理

JDK

IService

public interface Service {
    public void service(String name);
}

Service

public class ServiceImpl implements Service{
    public void service(String name){
        System.out.println("service with name : " + name);
    }
}

MyProxy

public class MyProxy<T> implements InvocationHandler {
    private T target;
    public MyProxy(T target){
        this.target = target;
    }
    public void before(){
        System.out.println("before");
    }
    public void after(){
        System.out.println("after");
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("service".equals(method.getName())){
            Object result = null;
            before();
            result = method.invoke(target, args);
            after();
            return result;
        }
        return method.invoke(target,args);
    }
    public T getProxy(){
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        return (T) Proxy.newProxyInstance(classLoader, interfaces, this);
    }
}

main

public class Main {
    public static void main(String[] args) {
        new MyProxy<Service>(new ServiceImpl()).getProxy().service("service");
    }
}

这样一来,是不是更亲民了,由原来的多对一,现在,能够满足一对多的场景了吧。

的确,似乎变得更好了,但是,没有想的那么好。

不足

main

public class Main {
    public static void main(String[] args) {
        System.out.println(new MyProxy<Service>(new ServiceImpl()).getProxy().getClass().getName());
    }
}

com.sun.proxy.$Proxy0。结果是这个,它的实体并不是Service

正是因为java中不允许多继承,然后就导致了它不得不利用作为顶层父类才能够进行对象的接收。

不能够进行无接口的对象的代理。

优点

  • 满足了装饰的目的
  • 实现了多对一的场景需求

诟病

  • 必须存在接口,并不适用全体(来了个好裁缝,只为一个团服务,这个就不好了吧)
  • 维护方面,还有待改进(大冷天的,换个衣服你也不能让我脱啊,会冻死的,还不如冷着)

CGLIB

proxy

public class Proxy<T> implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Proxy(T proto){
        enhancer.setSuperclass(proto.getClass());
        enhancer.setCallback(this);
    }
    public void before(){
        System.out.println("before");
    }
    public void after(){
        System.out.println("after");
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj, args);
        after();
        return result;
    }
    public T getProxy(){
        return (T)enhancer.create();
    }
}

main

public class Main {
    public static void main(String[] args) {
        new Proxy<Service>(new Service()).getProxy().service("hello");
    }
}

值得一说的是,cglib不仅可以代理接口,还可以对无接口类直接代理。

jdk代理有如下区别

  • jdk只能代理接口,cglib全能代理。
  • jdk基于反射,类生成高效;cglib基于字节码修改,执行高效。

遗漏

代理还需要替换原有对象,后期维护设计修改原逻辑。

这个问题,cglib并没有解决。莫不如说,这个就不是代理的工作范围。

不过spring提供了容器进行对象的管理和注入,从而解决了这个问题。

Autowired或者getBean的时候,是从容器中进行的对象获取。

刨除了手工创建对象的过程,是间接的引用的方式。

所以,在后期维护过程中,只需增添,而无需修改就能够完成想要的效果。

就像既定的代码增加日志,无需再打开原有的代码修改逻辑,也不用修改对象创建代码。

小结

  • 所谓代理(装饰)

对原型进行包装,在可辨识的程度内,在需要的地方注入操作(装饰)。

  • 所谓切面

在一个既定的可注入空代理的结构中,能够指定某个流程的具体操作办法。

也就是说,前面的都是代理,而AOP是在代理的成型框架中,对流程方法的指定。

Wrapper

public interface Wrapper {
    public void before();
    public void after();
}

proxy

public class Proxy<T> implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    private Wrapper wrapper = null;
    public void setWrapper(Wrapper wrapper){
        this.wrapper = wrapper;
    }
    public Proxy(T proto){
        enhancer.setSuperclass(proto.getClass());
        enhancer.setCallback(this);
    }
    public void before(){
        if(this.wrapper != null){
            this.wrapper.before();
        }
    }
    public void after(){
        if(this.wrapper != null){
            this.wrapper.before();
        }
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj, args);
        after();
        return result;
    }
    public T getProxy(){
        return (T)enhancer.create();
    }
}

大概就是这个意思。

AOP和代理并不冲突,也不是什么相似的东西。

AOP是在以实现生命周期代理为前提的情况下,对指定的生命周期进行定制方法注入。

所以,两者并不互斥,尤其是想要扩充方法,变得更加多变的情况下,这个时候装饰更加有用。

  • 装饰:针对类,可以收束到方法,针对原型进行扩充,操作插入和方法扩展。
  • 代理:针对流程,插入制定的前后置处理办法。
  • AOP: 在既定的生命代理框架下,对前后置操作处理办法进行注入。

方法扩展前后置处理,从这两点就能够很好的区分了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值