通俗易懂的讲解一下Java的代理模式如何实现

一、代理模式的基本介绍

何为代理模式呢?

就是为对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象,这样做的好处是可以在目标对象实现的基础上,增强额外的功能操作( 在调用这个方法前做前置处理,调用这个方法后 做后置处理。),即扩展对象的功能(类似明星需要经纪人一个道理,比如明星接广告,那么广告上需要和经纪人商量这事,而不是直接和明星去谈这件事)。

image-20200518205817345

二、代理模式的分类及实现

1、静态代理

静态代理在使用的时候,需要定义接口,被代理对象(目标对象)与代理对象一起实现相同的接口。

具体实现:

1、定义一个接口:UserManager,

2、真实对象UserManagerImpl实现UserManager接口,代理对象ProxyUserManager也实现UserManager

3、调用的时候通过调用代理对象的方法来调用目标对象

类结构图:

image-20200518211345498

//接口
public interface UserManager {

    void addUser(String userId, String userName);
   
}
//真实对象
public class UserManagerImpl implements UserManager {
    @Override
    public void addUser(String userId, String userName) {
        System.out.println("添加用户!!!!!!!");
    }

}
//代理对象
public class ProxyUserManager implements UserManager {
    private UserManager userManager;  //目标对象
    //构造器传递目标对象
    public ProxyUserManager(UserManager userManager) {
        this.userManager = userManager;
    }

    @Override
    public void addUser(String userId, String userName) {
        System.out.println("添加用户开始!!!!!!!!!!!!!!!");
        userManager.addUser(userId, userName);
        System.out.println("添加用户结束!!!!!!!!!!!!!!!!!");
    }

}
//客户端测试
public class ClientTest {

    public static void main(String[] args) {
        UserManager userManager=new ProxyUserManager(new UserManagerImpl());
        userManager.addUser("1","张三");
    }
}

优点:在不修改目标对象功能的前提下,能通过代理对象对目标对象实现功能的扩展

缺点:因为代理对象需要和目标对象实现一样的接口,所以会有很多代理对象

​ 一旦接口增加对象,目标对象与代理对象都要维护

2、动态代理(JDK)代理

代理对象不需要实现接口,但是目标对象需要实现接口,否则不能实现动态代理

代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象

方法说明:

ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

接口对象UserManager,目标对象UserManagerImpl同静态代理,代理类:ProxyFactory

public class ProxyFactory {

    private Object target; //目标对象

    public ProxyFactory(Object target) {
        this.target = target;   //对目标对象初始化
    }

    //给目标对象生成一个代理对象
    public Object getProxyInstance() {
        
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK代理开始!!!!!!");
                        Object obj = method.invoke(target, args);
                        System.out.println("JDK代理结束!!!!!");
                        return obj;
                    }
                });
    }

}

测试客户端:

public class Client {
    public static void main(String[] args) {
        //目标对象
        UserManager target = new UserManagerImpl();
        //创建代理对象
        UserManager proxyInstance = (UserManager) new ProxyFactory(target).getProxyInstance();
        proxyInstance.addUser("231", "zhangfu");
    }

}

3、动态代理(CJLIB)代理

静态代理和动态代理都需要目标对象实现一个接口,但有时候目标对象只是一个单独的对象,

并没有实现任何接口,这个时候就可以使用目标对象实现动态代理---CJLIB代理。

CJLIb代理是内存中构建一个子类对象从而实现对目标对象功能的扩展,Cjlib是一个强大的高性能的代码

生成包,它可以在运行期扩展java类与实现JAVA接口,广泛的应用在(SpringAOP)当中。

Cjlib 包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。

实例实现:

首先导入CJLIB 的架包

image-20200518221940520

代理类(ProxyFactory)需要实现MethodInterceptor接口,重写intercept()的方法。

代码实现:

public class UserManagerImpl  {

    public void addUser(String userId, String userName) {
        System.out.println("添加用户!!!!!!!");
    }

}
public class ProxyFactory implements MethodInterceptor {
    private Object target;  //目标对象

    public ProxyFactory(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[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("CJLIB代理开始");
        Object obj = method.invoke(target, objects);
        System.out.println("CJLIB代理结束");
        return obj;
    }
}

客户端测试

public class Client {
    public static void main(String[] args) {
        UserManagerImpl proxyInstance = (UserManagerImpl) new ProxyFactory(new UserManagerImpl()).getProxyInstance();
        proxyInstance.addUser("A", "AD");
    }
}

三、小结

在实际工作中:如果目标对象需要实现接口,采用静态代理,JDK代理

目标对象不需要实现接口,采用CJLIB代理

技术之路漫长,每天进步一丢丢

原文地址:https://www.cnblogs.com/xiaofuzi123456/p/12913581.html