在上一篇博客https://blog.youkuaiyun.com/weixin_39453325/article/details/84201400中我们详细讲解了静态代理模式,很显然静态代理有如下的缺点。
静态代理的缺点:因为代理对象需要与目标对象实现一样的接口,一般一个目标对象类需要对应一个代理类,所以会有很多代理类,类太多,不易管理。同时,一旦接口增加方法,目标对象与代理对象都要维护。
解决方法:使用动态代理,其实动态代理与静态代理的思想是一样的,动态代理与静态代理的区别是,动态代理不用我们为每一个接口去编写特定的代理类,在运行时,动态的在内存中产生代理类。
动态代理
动态代理是一种较为高级的代理模式,它的典型应用就是 Spring AOP。
在传统的代理模式中,客户端通过 Proxy 调用 RealSubject 类的 request() 方法,同时还在代理类中封装了其他方法(如 preRequest() 和 postRequest() ),可以处理一些其他问题。如果按照这种方法使用代理模式,那么真实主题角色必须是事先已经存在的,并将其作为代理对象的内部成员属性,如果一个真实主题角色必须对应一个代理主题角色,这将导致系统中类的个数急剧增加,因此需要想办法减少系统中类的个数,此外,如何在事先不知道真实主题角色的情况下使用代理主题角色,这都是动态代理需要解决的问题。
Java 动态代理实现相关类位于 java.lang.reflect 包,主要涉及两个类:
-- InvocationHandler 接口。它是代理实例的调用处理程序实现的接口,该接口中定义了如下方法:
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
invoke() 方法中的第一个参数 proxy 表示代理类,第二个参数 method 表示需要代理的方法,第三个参数 args 表示代理方法的参数数组。
-- Proxy 类。该类即为动态代理类,该类最常用的方法为:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IIIegalArgumentException;
newProxyInstance() 方法用于根据传入的接口类型 interfaces 返回一个动态创建的代理类的实例,方法中第一个参数 loader 表示代理类的类加载器,第二个参数 interfaces 表示代理类实现的接口列表(与真实主题类的接口列表一致),第三个参数 h 表示所指派的调用处理程序类。
代理模式实例与解析
本处的实例来自上篇静态代理的实例一https://blog.youkuaiyun.com/weixin_39453325/article/details/84201400,学者可参考比较来学习。
接口类:
/**
* 接口方法
* @author 14517
*
*/
public interface UserManager {
public void addUser(String username,String password);
public void deleteUser(int id);
public void modifyUser(int id,String username,String password);
public String findUserById(int id);
}
目标类 :
/**
* 实现 UserManager 接口
* @author 14517
*
*/
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String username, String password) {
System.out.println("---UserManagerImpl addUser()---");
}
@Override
public void deleteUser(int id) {
System.out.println("---UserManagerImpl deleteUser()---");
}
@Override
public void modifyUser(int id, String username, String password) {
System.out.println("---UserManagerImpl modifyUser()---");
}
@Override
public String findUserById(int id) {
System.out.println("---UserManagerImpl findUserById()---");
return null;
}
}
代理类(动态代理,代理类没有实现和目标对象一样的接口,而是通过 JavaAPI 在内存中为我们动态创建一个代理对象) :
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* jdk 动态代理,只要实现 InvocationHandler 接口,即可代理所有接口
* @author 14517
*
*/
public class DynamicProxyHandler implements InvocationHandler {
/**
* 目标对象
*/
private Object targetObject;
/**
* @param object
* @return 代理对象
*/
public Object newProxy(Object object) {
this.targetObject=object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
this);
}
/**
* @param proxy 代理类
* @param method 需要代理的方法
* @param args 代理方法的参数组
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
checkBefore();
Object ret=method.invoke(this.targetObject,args);
checkAfter();
return ret;
}
/**
* 方法执行之前调用
*/
public void checkBefore() {
System.out.println("---Before---");
}
/**
* 方法执行之后调用
*/
public void checkAfter() {
System.out.println("---After---");
}
}
测试类:
/**
* 动态代理测试
* @author 14517
*
*/
public class DynamicProxyTest {
public static void main(String[] args) {
DynamicProxyHandler handler=new DynamicProxyHandler();
UserManager um=(UserManager) handler.newProxy(new UserManagerImpl());
um.addUser("DynamicProxyHandler", " ");
um.deleteUser(1);
um.modifyUser(1, "DynamicProxyHandler", " ");
um.findUserById(1);
}
}
执行程序,输出结果: