【结构型】- 代理模式

代理模式的定义:

  为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式可以分为三种:静态代理,动态代理,cglib动态代理。

静态代理

服务接口

package com.java.pattern.proxy.staticdemo;

public interface UserService {
    void eat();
}

服务具体实现(委托类)

package com.java.pattern.proxy.staticdemo;

public class UserServiceImpl implements UserService {
    @Override
    public void eat() {
        System.out.println("感谢上帝,感谢神,我开动了...");
    }
}

服务静态代理类

package com.java.pattern.proxy.staticdemo;

public class UserProxyServiceImpl implements UserService {
    
    private UserService userService;

    public UserProxyServiceImpl(UserService userService) {
        this.userService = userService;
    }
    
    @Override
    public void eat() {
        System.out.println("先点外卖.....");
        userService.eat();
        System.out.println("清理外卖.....");
    }

}

测试类

package com.java.pattern.proxy.staticdemo;

public class Ctest01 {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();// 使用静态代理,在不改变eat()方法代码的前提下,增强功能(添加额外的功能服务)
        userService = new UserProxyServiceImpl(userService);
        userService.eat();
    }
}

测试结果:

先点外卖.....
感谢上帝,感谢神,我开动了...
清理外卖.....

优点:

  • 在不改变委托类代码的前提下,为委托类添加额外的功能。

缺点:

  • 代理类和委托类需要实现同一接口。
  • 一个代理类只能代理一个服务,这就导致我们需要为每一个服务都创建代理类。
  • 委托类实现的接口,一旦发生改变,代理类也要修改代码。

jdk动态代理

  JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。

动态代理类

public class DynamicProxyService implements InvocationHandler {
    private Object target;

    public DynamicProxyService(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理类[DynamicProxyService] before doSomething...");
        Object res = method.invoke(target, args);
        System.out.println("代理类[DynamicProxyService] after doSomething...");
        return res;
    }
}

代理的目标对象:接口的实现类

public interface TargetService {

    String doSomething(String params);
    
}
public class TargetServiceImpl implements TargetService {

    @Override
    public String doSomething(String params) {
        System.out.println("[TargetServiceImpl]doSomething..."); return null; } }

代理的目标对象:类的继承类(子类)

public class TargetClass {

    /**
     * 普通方法
     */
    public void doSomething() {
        System.out.println("[TargetClass]doSomething...");
    }

    /**
     * final方法
     */
    public final void finalFunction() {
        System.out.println("[TargetClass]finalFunction...");
    }
    
}
public class TargetSubClass extends TargetClass {

    @Override
    public void doSomething() {
        System.out.println("[TargetSubClass]doSomething...");
    }

}

测试类:

public class Ctest01 {

    public static void main(String[] args) {
        testJDKDynamicProxy();
    }

    public static void testJDKDynamicProxy() {
        System.out.println("---> 代理对象:接口的实现类");
        // 目标类
        TargetService targetService = new TargetServiceImpl();
        // 代理类
        DynamicProxyService dynamicProxyService = new DynamicProxyService(targetService);
        // 获取代理对象
        targetService = (TargetService)dynamicProxyService.getProxyInstance();
        targetService.doSomething("params");
        System.out.println("----------------------------------------------------------------");
        System.out.println("---> 代理对象:继承类");
        // 目标类
        TargetClass targetClass = new TargetSubClass();
        // 代理类
        dynamicProxyService = new DynamicProxyService(targetClass);
        // 获取代理对象
        targetClass = (TargetClass) dynamicProxyService.getProxyInstance();
        targetClass.doSomething();
    }

}

测试结果:

---> 代理对象:接口的实现类
代理类[DynamicProxyService] before doSomething...
[TargetServiceImpl]doSomething...
代理类[DynamicProxyService] after doSomething...
----------------------------------------------------------------
---> 代理对象:继承类
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy1 cannot be cast to com.design.pattern.proxy.target.TargetClass
    at com.design.pattern.proxy.Ctest01.testJDKDynamicProxy(Ctest01.java:43)
    at com.design.pattern.proxy.Ctest01.main(Ctest01.java:15)

优点:

  • 在不改变委托类代码的前提下,为委托类添加额外的功能。
  • 代理类无需和委托类实现同一接口。
  • 一个代理类能够代理所有委托类

缺点:

  • 委托类必须要实现某一接口或继承某一父类

cglib动态代理

  JDK实现动态代理需要目标类实现某一接口,对于没有实现任何接口的类,该如何实现动态代理呢,这就需要CGLib了,CGLIB(Code Generation Library)是一个代码生成的类库。采用了非常底层的字节码技术,其原理是通过字节码技术在运行时为指定类创建一个子类对象,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的目标类,以及目标类中的final方法进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

委托类

public class TargetClass {

    /**
     * 普通方法
     */
    public void doSomething() {
        System.out.println("[TargetClass]doSomething...");
    }

    /**
     * final方法
     */
    public final void finalFunction() {
        System.out.println("[TargetClass]finalFunction...");
    }

}

cglib代理类

package com.design.pattern.proxy.cglibmode;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyService implements MethodInterceptor {

private Object target;

public CglibProxyService(Object target) {
this.target = target;
}

public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理类[CglibProxyService] before doSomething...");
Object res = method.invoke(target, args);
System.out.println("cglib代理类[CglibProxyService] after doSomething...");
return res;
}
}

测试类

package com.design.pattern.proxy;

import com.design.pattern.proxy.cglibmode.CglibProxyService;
import com.design.pattern.proxy.jdkmode.DynamicProxyService;
import com.design.pattern.proxy.staticmode.ProxyService;
import com.design.pattern.proxy.target.TargetClass;
import com.design.pattern.proxy.target.TargetService;
import com.design.pattern.proxy.target.TargetServiceImpl;
import com.design.pattern.proxy.target.TargetSubClass;

public class Ctest01 {

    public static void main(String[] args) {
        testCglibProxy();
    }

    public static void testCglibProxy() {
        // 目标类
        TargetClass targetClass = new TargetClass();
        // 代理类
        CglibProxyService cglibProxyService = new CglibProxyService(targetClass);
        // 获取代理对象
        targetClass = (TargetClass)cglibProxyService.getProxyInstance();
        targetClass.doSomething();
        // 测试cglib动态代理是否能代理final方法
        targetClass.finalFunction();
    }

}

测试结果如下:

cglib代理类[CglibProxyService] before doSomething...
[TargetClass]doSomething...
cglib代理类[CglibProxyService] after doSomething...
[TargetClass]finalFunction...

优点:

  • 在不改变委托类代码的前提下,为委托类添加额外的功能。
  • 代理类无需和委托类实现同一接口。
  • 一个代理类能够代理所有委托类
  • 相比于JDK动态代理,委托类无需要实现某一接口或继承某一父类。

缺点:

  • 委托类不能是final类,因为final类无法被继承。
原文地址:https://www.cnblogs.com/517cn/p/10878118.html