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

java

一、代理模式的基本介绍

何为代理模式呢?

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

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

1、静态代理

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

具体实现:

1、定义一个接口:UserManager,

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

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

类结构图:

//接口

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 的架包

代理类(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代理

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

以上是 通俗易懂的讲解一下Java的代理模式如何实现 的全部内容, 来源链接: utcz.com/z/390425.html

回到顶部