美文网首页spring aop程序员
Spring AOP浅析(一):代理模式及实现

Spring AOP浅析(一):代理模式及实现

作者: MagicWolf | 来源:发表于2016-05-07 20:35 被阅读2106次

Spring AOP 是代理模式的应用,可以使用JDK提供的Proxy类或通过字节码增强来实现。想要知道Spring如何实现AOP就必须要先了解代理模式。

1 代理模式

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问;
使用代理模式创建代理对西安,让代理对象控制某对象的访问,被代理的对象可以是远程对象,创建开销大的对象或需要安全控制的对象

--《Head First 设计模式》

1.1 UML类图

2 代理模式实现

参照上面的UML类图,先写出Subject接口和实际对象

//抽象角色
public interface Subject {
    public void request(String param);
}

//目标角色
public class RealSubject implements Subject{
    @Override
    public void request(String param) {
        System.out.println("param:"+param);
    }
}

2.1 静态代理

静态代理的实现很简单,对目标角色进行封装,并拦截方法调用。这里实现一个参数验证的代理逻辑

public class StaticProxy implements Subject{
    Subject  realSubject;
    public StaticProxy(Subject  realSubject) {
        this.realSubject=realSubject;
    }
    public void before(String param){
        if(!param.equals("magicalwolf"))//验证参数
            throw new IllegalArgumentException();
    }
    @Override
    public void request(String param) {
        before(param);
        realSubject.request(param);
    }
}

public class Main {
    public static void main(String[] args) {
        Subject target=new RealSubject();
        Subject proxy=new StaticProxy(target);
        proxy.request("magicalwolf");
        proxy.request("hello");
    }
}

输出:param:magicalwolf
    Exception in thread "main" java.lang.IllegalArgumentException
    ......

静态代理的实现为每个实际对象都产生一个代理类,并将其作为内部属性。这会导致类数量的急速增加,并且代理类的代码存在大量重复。这就需要动态代理来实现。

2.2 动态代理

2.2.1 通过JDK实现

JDK提供的动态代理需要实现InvocationHandler接口的invoke方法.此方法为整个代理的入口。方法签名为

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

第一个参数是代理对象,第二个参数是目标方法,第三个参数是目标方法参数

public class ProxyHandler implements InvocationHandler{
    Object target;
    public ProxyHandler(Object target) {
        this.target=target;
    }
    public void before(String param) throws Throwable{
        if(!param.equals("magicalwolf"))
            throw new IllegalArgumentException();
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        before((String)args[0]);
        return method.invoke(target, args);
    }
}

之后通过Proxy类的newProxyInstance方法创建代理对象

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

第一个参数是目标对象的类加载器,第二个参数是目标类实现的接口,第三个参数是处理器InvocationHandler

public class Main {
    public static void main(String[] args) {
        Subject target=new RealSubject();
        Subject proxy=(Subject)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new ProxyHandler(target));
        proxy.request("magicalwolf");
        proxy.request("hello");
    }
}
输出:与静态代理一样

可以看到使用JDK提供的动态代理无需为每个对象都实现一个代理类,通过处理器,可以对不同的对象生成代理类。

处理器只关注处理逻辑,并且可以重用,上面的例子中处理器用于参数检查,与某种格式的请求方法耦合在一起,如果需要对不同的方法进行,需要写多个处理器,但是还是比静态代理方便很多。

对于更通用的功能,比如日志记录,调用次数统计,一个处理器就可以代理所有的对象。

注:但是JDK的动态代理是通过代理接口实现的,如果对象没有实现接口,那就无能为力了

2.2.2 通过字节码增强实现(CGLIB)

CGLIB是一个强大的高性能的代码生成包,在运行时动态生成字节码并生成新类。

CGLIB提供了MethodInterceptor接口,当调用目标方法时被回调,类似于InvocationHandler.

public class RequestInterceptor implements MethodInterceptor{

    public void before(String param) throws Throwable{
        if(!param.equals("magicalwolf"))
            throw new IllegalArgumentException();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        before((String)args[0]);
        return proxy.invokeSuper(obj, args);//调用父类的方法
    }
}

生成代理类

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer(); //字节码增强器
        enhancer.setSuperclass(RealSubject.class);  //代理类
        enhancer.setCallback(new RequestInterceptor());//回掉方法  
        Subject proxy=(Subject) enhancer.create();
        proxy.request("magicalwolf");
        proxy.request("hello");
    }
}

可以看到,CGLIB是通过动态生成目标类的子类,在子类中设置拦截逻辑,来进行动态代理。因此目标类的方法不能被final修饰。

2.3 代理模式与装饰者模式

从UML上看装饰者模式和代理模式很像,装饰者和代理者都对目标方法进行修改,但是二者还是有很大的区别。

  • 装饰者模式关注于对目标方法进行增强。装饰者只能在外加一层装饰。
  • 代理模式关注于对目标方法的控制。代理者拥有控制权限,可以决定目标方法是否调用。

相关文章

  • Spring AOP浅析(一):代理模式及实现

    Spring AOP 是代理模式的应用,可以使用JDK提供的Proxy类或通过字节码增强来实现。想要知道Sprin...

  • Spring Aop、拦截器、过滤器的区别

    Spring AOP Spring AOP,是AOP的一种实现,使用的是代理模式。 Filter Filter(过...

  • 静态代理和动态代理

    代理模式是Java模式中很重要的一个。特别是动态代理模式是Spring AOP实现的基石,也是我们理解AOP原理的...

  • Spring AOP 实现原理

    Spring AOP 实现原理 静态代理 众所周知 Spring 的 AOP 是基于动态代理实现的,谈到动态代理就...

  • Spring AOP 学习笔记(1) ---- 代理模式

    参考文章 spring aop 官方文档 掘金spring aop 教程 掘金动态代理 代理模式分类 根据代理类的...

  • Spring 学习--AOP

    参考文献:深入浅析Spring 的aop实现原理Spring AOP 深入剖析AOP: 面向切面编程oop是从上往...

  • 带你初识Java的代理模式

    Spring AOP是基于动态代理设计模式实现的,相对的就有静态代理 动态代理和静态代理 静态代理 对于静态代理,...

  • 2020-02-26

    Spring的AOP代理模式 三种实现 1. 通过Proxy的newProxyInstance(类加载器,代理对象...

  • 2018-09-16

    AOP的XML配置: AOP的先关术语: Spring底层的AOP实现原理 动态代理: JDK动态代理:只能对实现...

  • Spring AOP

    Spring AOP是代理模式的经典实现,代理模式的作用就是把一些目标类没有的功能附加到代理类上,然后在代理类上执...

网友评论

    本文标题:Spring AOP浅析(一):代理模式及实现

    本文链接:https://www.haomeiwen.com/subject/olhsrttx.html