侧边栏壁纸
博主头像
实习两年半

基础不牢,地动山摇。

  • 累计撰写 43 篇文章
  • 累计创建 40 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

代理模式

实习两年半
2022-06-11 / 0 评论 / 0 点赞 / 254 阅读 / 1,440 字
温馨提示:
本文最后更新于 2022-06-12,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

介绍

 代理模式通过创建一个代理类,来对目标类进行增强。这样可以在不修改目标类的情况下进行扩展。比如在对目标对象的某个方法前后执行一些操作。
代理模式
 而代理模式分为静态代理和动态代理,动态代理主要有jdk动态代理和cjlib动态代理。其中jdk动态代理是java自带的,不需要额外的引入第三方包;而cjlib动态代理属于一个开源项目,使用的话需要导入相关依赖。

静态代理

特点

  1. 静态代理在编译期间就将接口、实现类、代理类都编译成一个个class文件。
  2. 静态代理对每个方法增强都需要自己手动实现,并且目标类和代理类都需要进行修改。所以在日常使用中很少使用,以至于基本看不到。
  3. 静态代理需要对每一个目标类单独写一个代理类。

实现方式

  1. 定义一个接口及其实现类;
  2. 创建一个代理类同样实现这个接口
  3. 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法(可以在调用前后添加自己的需要的代码)。

代码实现
1.定义接口

public interface HelloService {
    void hello();
}

2.实现类

public class HelloServiceImpl implements HelloService{
    @Override
    public void hello() {
        System.out.println("hello world!");
    }
}

3.创建代理类并同样实现接口
 通过构造函数注入需要代理的目标类

public class HelloProxy implements HelloService{

    private final HelloService helloService;

    public HelloProxy(HelloService helloService){
        this.helloService = helloService;
    }

    @Override
    public void hello() {
        System.out.println("before......");
        helloService.hello();
        System.out.println("after......");
    }
}

  1. 测试类
public class HelloMainTest {
    public static void main(String[] args) {
        HelloService helloService = new HelloServiceImpl();
        HelloProxy helloProxy = new HelloProxy(helloService);
        helloProxy.hello();
    }
}

5.执行结果

before......
hello world!
after......

jdk动态代理

 jdk动态代理用到InvocationHandler接口和Proxy类。其Proxy类中的newProxyInstance()方法是关键,该方法用来生成一个代理对象。

  public static Object newProxyInstance(
    ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h)
  1. loader :类加载器,用于加载代理对象。
  2. interfaces : 被代理类实现的一些接口;
  3. h : 实现了 InvocationHandler 接口的对象;

 要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

public Object invoke(Object proxy, Method method, Object[] args)
  1. proxy :动态生成的代理类
  2. method : 与代理类对象调用的方法相对应
  3. args : 当前 method 方法的参数

你通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。可以在invoke()方法中自定义代码逻辑。

代码实现

  1. 定义一个接口及其实现类;
  2. 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象(一般是通过工厂模式来创建对象)

定义接口

public interface HelloService {
    void hello();
}

接口实现类

public class HelloServiceImpl implements HelloService {

    @Override
    public void hello() {
        System.out.println("hello......");
    }
}

创建代理类并实现InvocationHandler接口

public class HelloJdkProxy implements InvocationHandler {

    private final Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //调用方法之前,我们可以添加自己的操作
        System.out.println("before method " + method.getName());

        Object result = method.invoke(target, args);

        //调用方法之后,我们同样可以添加自己的操作
        System.out.println("after method " + method.getName());

        return result;
    }
}

这里通过工厂类来创建代理对象

public class JdkProxyFactory {

    public static Object getJdkProxy(Object target){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), // 目标类的类加载
                target.getClass().getInterfaces(),  // 代理需要实现的接口,可指定多个
                new HelloJdkProxy(target)   // 代理对象对应的自定义 InvocationHandler
        );
    }
}

测试

public class TestMainProxy {
    public static void main(String[] args) {

        HelloService jdkProxy = (HelloService)JdkProxyFactory.getJdkProxy(new HelloServiceImpl());
        jdkProxy.hello();
    }

}

运行结果

before method hello
hello......
after method hello

CJLIB动态代理

 对于jdk动态代理,代理的对象必须是一个实现接口的类,这就存在了很大的限制,而CJLIB动态代理没有可以解决这个问题。

实现步骤

  1. 定义一个类;
  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
  3. 通过 Enhancer 类的 create()创建代理类;

添加依赖

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>

目标类

public class HelloService {

    public void hello(){
        System.out.println("hello ......");
    }
}

代理类

public class HelloProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //调用方法之前,我们可以添加自己的操作
        System.out.println("before method ......");
        Object object = methodProxy.invokeSuper(o, objects);
        //调用方法之后,我们同样可以添加自己的操作
        System.out.println("before method ......");
        return object;
    }
}

获取代理对象的工厂类

public class CjlibProxyFactory {

    public static Object getProxy(Class<?> clazz){
        // 创建动态代理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(clazz);
        // 设置方法拦截器
        enhancer.setCallback(new HelloProxy());
        // 创建代理类
        return enhancer.create();
    }
}

测试类


public class TestMainProxy {

    public static void main(String[] args) {
        HelloService proxy = (HelloService)CjlibProxyFactory.getProxy(HelloService.class);
        proxy.hello();
    }
}

执行结果

before method ......
hello ......
before method ......
0

评论区