java的代理模式

java的三种代理模式

  • 简介
  • 静态代理
  • jdk动态代理
  • cglib实现动态代理

简介

代理模式的定义: 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
以上为百度百科对代理模式的定义;通俗一点讲,java中的代理模式就是你想要访问一个目标对象,但是不直接访问它,而是通过它的代理对象访问(因为代理对象可以对目标对象做增强操作),这就是java的代理模式。示意图如下:
java的代理模式_第1张图片

在java中,有三种代理模式,分别为静态代理,动态代理,cglib代理。

静态代理

先创建一个父类或者接口,被代理对象和代理对象都应该继承父类或者实现接口。
创建接口Movie.java

public interface Movie {
    void play();
}

创建实现类RealMovie.java

public class RealMovie implements Movie {
    @Override
    public void play() {
        System.out.println("播放金刚大战哥斯拉");
    }
}

创建代理类ProxyMovie.java

public class ProxyMovie implements Movie {
    Movie movie;

    public ProxyMovie(Movie movie) {
        this.movie = movie;
    }

    @Override
    public void play() {
        System.out.println("电影还没开始,买点爆米花");
        movie.play();
        System.out.println("电影结束了,买个哥斯拉模型");
    }
}

创建测试类Test.java

public class Test {
    public static void main(String[] args) {
        RealMovie movie = new RealMovie();
        ProxyMovie proxyMovie = new ProxyMovie(movie);
        proxyMovie.play();
    }
}

运行结果
在这里插入图片描述
总结:在不改变RealMovie的前提下,使用ProxyMovie对其进行了增强。但是由于目标对象和代理对象都实现了同一个接口,一旦这个接口添加或者删除方法,那么代理对象和目标对象都要进行相应的操作,耦合度太高。
静态代理的应用:在使用实现Runnable接口实现多线程的时候,将Runnable接口的实现类的对象作为Thread的构造函数的参数;
java的代理模式_第2张图片

jdk动态代理

为了解决静态代理的代理类必需实现接口的所有方法的问题,动态代理诞生了,java的动态代理有如下的特点:
1、代理对象不需要跟目标对象实现同一接口或继承同一个父类(解决了静态代理的痛点);
2、代理对象的生成利用jdk提供的api,在JVM内存中动态的构建代理对象。
创建接口Movie.java

public interface Movie {
    void play();
}

创建实现类RealMovie.java

public class RealMovie implements Movie{
    @Override
    public void play() {
        System.out.println("播放侏罗纪世界");
    }
}

创建代理类ProxyMovie.java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ProxyMovie implements InvocationHandler {
    private Object movie;

    public ProxyMovie(Object movie) {
        this.movie = movie;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("电影还没开始,买瓶可乐");
        method.invoke(movie, args);
        System.out.println("电影还结束,买一只恐龙模型");
        return null;
    }
}

创建测试类Test.java

public class Test {
    public static void main(String[] args) {
        RealMovie realMovie = new RealMovie();
        InvocationHandler proxyMovie = new ProxyMovie(realMovie);
        // 创建代理对象
        Movie movie = (Movie)Proxy.newProxyInstance(realMovie.getClass().getClassLoader(), realMovie.getClass().getInterfaces(), proxyMovie);
        System.out.println(movie.getClass().getSimpleName());
        movie.play();
    }
}

运行结果
java的代理模式_第3张图片
总结:在这里,代理类没有实现Movie接口,而是实现了InvocationHandler接口,然后重写了invoke方法,与Movie接口的耦合度降低。

cglib实现动态代理

在使用jdk动态代理时,被代理对象是实现了一个接口的,假如实际中被代理对象没有实现接口该怎么办呢,cglib动态代理便应运而生,原理是创建一个目标对象的子类对象,然后进行增强操作,所以被代理对象的类不能是final类型的(无法被继承,也就没有子类),被调用的方法也不能是final和static类型的(不会执行代理功能)。
在pom.xml文件中添加cglib依赖

<dependency>
	<groupId>cglibgroupId>
	<artifactId>cglibartifactId>
	<version>3.3.0version>
dependency>

创建CglibService.java

public class CglibService {
    public void movie() {
        System.out.println("播放侏罗纪公园");
    }
}

创建CglibServiceProxy.java类

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibServiceProxy implements MethodInterceptor {
    private Object object;

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

    public Object getProxyInstance() {
        //创建代理类
        Enhancer enhancer = new Enhancer();
        //继承要被代理的类
        enhancer.setSuperclass(object.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("电影即将开始,大家有序进入影厅");
        Object obj = method.invoke(object);
        System.out.println("电影结束,大家离开电影院");
        return obj;
    }
}

创建CglibProxyTest.java

public class CglibProxyTest {
    public static void main(String[] args) {
        CglibService service = new CglibService();
        CglibServiceProxy proxy = new CglibServiceProxy(service);
        CglibService proxyInstance = (CglibService)proxy.getProxyInstance();
        proxyInstance.movie();
    }
}

运行结果
java的代理模式_第4张图片
总结:由以上可以看出,使用cglib代理可以代理一些没有父类的目标对象,所以以后如果要代理没有实现接口的类,可以选择使用cglib代理。

你可能感兴趣的:(java,代理,代理模式,java,开发语言)