what? why?
代理对象控制
对真实对象的访问,so,为什么需要进行访问控制?
- 在某些情况下,一个客户不想或不能直引用另一对象,如使用dubbo调用远程服务
- 代理对象可以添加功能,进行权限控制;如我司通过代理控制对es的访问,以实现权限控制和流量控制等功能.
- 参考: https://www.cnblogs.com/silverLee/archive/2010/02/05/1664577.html
How:
代理模式有3种角色:
- 抽象角色:声明真实对象和代理对象之间的共同接口,用来规范代理对象的行为;
- 代理角色:内部含有对真实对象的引用;提供和真实对象一致的接口以便在任何时候都能代替真实对象;可以在执行真实对象的操作时附加操作。
- 真实角色:真实对象,被代理。
静态代理
静态代理是指代理角色在运行之前已经存在,即运行前需要编码编译
//客户端
public class Client
{
public static void main(String[] args)
{
Subject subject = new ProxySubject();
subject.request();
}
}
//抽象角色,代理角色和真实角色都实现或继承他
public abstract class Subject
{
public abstract void request();
}
//代理角色
public class ProxySubject extends Subject
{
private RealSubject realSubject; //真实角色的引用
public void request()
{
//附加功能
this.preRequest();
if(null == realSubject)
{
realSubject = new RealSubject();
}
realSubject.request();
this.postRequest();
}
private void preRequest()
{
System.out.println("pre request");
}
private void postRequest()
{
System.out.println("post request");
}
}
//真实角色
public class RealSubject extends Subject
{
public void request()
{
System.out.println("From real subject.");
}
}
why动态代理?
- 就静态代理而言:
一个真实角色必须对应一个代理角色
,大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这些问题可以通过动态代理来解决,所谓动态代理是指代理角色在运行时动态生成
的技术。 - 采用动态代理,一个
InvocationHandler接口的实例
可以代理不同的对象,也就是说相同的代理逻辑只用写一次代码
java动态代理框架
- 由java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy组成,
InvocationHandler接口实例
和Proxy.newProxyInstance生成的对象实例
进行不同分工,一起充当了代理角色。 InvocationHandler实例
只有一个invoke方法
,负责调用真实对象的方法Proxy
会将真实对象注入到InvocationHandler实例
;Proxy在运行时动态生成和真实对象具有相同接口的代理对象,然后调用
InvocationHandler实例的
invoke`方法;Proxy
运行时生成代理类的字节码的动作由sun.misc.ProxyGenerator.generateProxyClass()
完成
一个实例
public class Client
{
public static void main(String[] args)
{
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
Class<?> classType = handler.getClass();
Subject subject = (Subject) Proxy.newProxyInstance(classType
.getClassLoader(), realSubject.getClass().getInterfaces(),
handler);
subject.request();
System.out.println(subject.getClass());
}
}
public class DynamicSubject implements InvocationHandler
{
private Object sub;
public DynamicSubject(Object obj)
{
this.sub = obj;
}
//正是由于这里采用了反射,所以才避免了静态代理和真实对象绑定的//问题。
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("before calling: " + method);
method.invoke(sub, args);
System.out.println(args == null);
System.out.println("after calling: " + method);
return null;
}
}
public class RealSubject implements Subject
{
public void request()
{
System.out.println("From real subject!");
}
}
//一致性接口,真实对象和动态生成的代理对象都要实现。
public interface Subject
{
public void request();
}
另一个例子: 代理List
public class Client<T> implements InvocationHandler{
T obj;
public Client(T obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("Proxy!");
return method.invoke(obj,args);
}
public static void main(String[] args) {
List<Integer> list = new LinkedList<>();
Client<List<Integer>> handler = new Client<>(list);
//pro为动态生成的代理对象
@SuppressWarnings("unchecked")
List<Integer> pro = (List<Integer>)Proxy.newProxyInstance(Handler.class.getClassLoader(),
list.getClass().getInterfaces(),handler);
//通过代理pro调用add方法。pro会让handler通过调用invoke调用add方法
for(int i=0;i<10;i++)
pro.add(i);
for(Iterator<Integer> it =pro.iterator();it.hasNext();System.out.print(it.next()));
}
}