通俗易懂的讲解一下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代理
技术之路漫长,每天进步一丢丢