代理模式01-初体验

定义

Proxy Pattern 是一种结构模式,指为其余对象提供一种代理以控制对这个对象的访问。java

类图

image

代理模式通常包含三种角色: node

Subject:
定义的RealSubject和Proxy的共有方法,这个类能够是接口,也能够是抽象类。这样全部使用RealSubject的地方均可以用Proxy代替。框架

RealSubject:
被代理类,此类定义了真实的Subject实现。ide

Proxy:
代理类通常要持有一个被代理的对象的引用,并可能负责建立和删除被代理对象。性能

静态代理和动态代理

代理模式的实现大致上能够分为两种,一种是静态代理,一种是动态代理。两种代理从JVM加载类的角度来说,本质上都是同样的。this

静态代理

上面的类图就是传统的静态代理,代码不贴了。(然而相关代码接下来的demo里有用到。)spa

优势:.net

  • 实现简单。

缺点:代理

  • 静态代理只能经过手动完成被代理对象的注入。
  • 若是被代理类增长了新的方法,代理类须要同步增长,违背了开闭原则。
  • 一个代理类只能处理一个被代理类。

动态代理

JAVA的SDK中已经有了实现方法,Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);
使用JDK动态代理须要注意,目标类必须实现的某个接口,若是某个类没有实现接口则不能生成代理对象。 code

优势:

  • 动态代理扩展性好。

    • 动态代理采用在运行时动态生成字节码的方式,取消了被代理类的扩展限制,遵循开闭原则。
  • 被代理对象自动注入。

缺点:

  • 执行效率相对要低,每次都要反射动态调用控。
代码示例
public static class SubjectInvocationHandler implements InvocationHandler {

    private Object object;

    public SubjectInvocationHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before 动态代理...");
        System.out.println(proxy.getClass().getName());
        System.out.println(this.object.getClass().getName());
        return method.invoke(object, args);
    }
}

public static void main(String[] args) {
    Subject o = (Subject) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Subject.class}, new SubjectInvocationHandler(new RealSubject()));
    o.request();
}

Cglib动态代理

添加Maven依赖
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>2.2</version>
</dependency>
代码示例
public static void main(String[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(RealSubject.class);
    enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {
        System.out.println("before method run...");
        Object result = proxy.invokeSuper(obj, args1);
        System.out.println("after method run...");
        return result;
    });
    RealSubject subject = (RealSubject) enhancer.create();
    subject.request();
}

Cglib原理是针对目标类生成一个子类,覆盖其中的全部方法,因此目标类和方法不能声明为final类型。
Cglib采用ASM框架写Class字节码,实现比JDK复杂,因此生产代理类比JDK动态代理效率低。
JDK是采用反射机制调用的,而CGLib经过FastClass机制直接调用方法,因此只需效率更高。

FastClass

FastClass不使用反射类(Constructor或Method)来调用委托类方法,而是动态生成一个新的类(继承FastClass),向类中写入委托类实例直接调用方法的语句,用模板方式解决Java语法不支持问题,同时改善Java反射性能。

动态类为委托类方法调用语句创建索引,使用者根据方法签名(方法名+参数类型)获得索引值,再经过索引值进入相应的方法调用语句,获得调用结果。

Spring中的代理选择原则

  • 当Bean有实现接口时,Spring就会调用JDK动态代理。
  • 当Bean没有实现接口时,Spring会选择CGLib代理。
  • Spring能够经过配置强制使用CGLib代理。

补充阅读

警戒动态代理致使的Metaspace内存泄漏问题

https://blog.csdn.net/xyghehe...

相关文章
相关标签/搜索