2019年7月28日
目录
写在开头
静态代理实现
动态代理实现
剖析动态反射 Proxy.newProxyInstance
写在末尾
写在开头
代理模式可以有两种实现的方式,一种是静态代理类,另一种是各大框架都喜欢的动态代理。下面以java语言为例,给大家详细解释代理模式的用法。
结构型模式讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象实现新的功能(对象结构型模式)。
代理模式(Proxy):为其他对象提供一种代理以控制对该对象的访问。
静态代理实现
静态代理即使用静态类来代理各种类的动作。
- 创建接口
Subject
public interface Subject {
//需求一
void visit();
//需求二
void gohome();
//需求三四五六...
}
- 创建实现类1
RealSubject implements Subject
public class RealSubject implements Subject {
private String name = "mmb";
@Override
public void visit() {
System.out.println("my name is "+name);
}
@Override
public void gohome() {
System.out.println("i am "+name + ",i want to go back home.");
}
}
RealSubject2 implements Subject
public class RealSubject2 implements Subject {
private String name = "mmb2";
@Override
public void visit() {
System.out.println("my name is "+name);
}
@Override
public void gohome() {
System.out.println("i am "+ name + ",i do not want to go back home.");
}
}
- 创建代理类(实现接口的所有操作)
ProxySubject implements Subject
public class ProxySubject implements Subject {
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void visit() {
subject.visit();
}
@Override
public void gohome() {
subject.gohome();
}
public void setSubject(Subject subject) {
this.subject = subject;
}
}
- 创建测试用例 test
public class test {
public static void main(String[] args){
ProxySubject proxySubject = new ProxySubject(new RealSubject());
proxySubject.visit();
proxySubject.gohome();
proxySubject.setSubject(new RealSubject2());
proxySubject.visit();
proxySubject.gohome();
}
}
/**
* 通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。
* 但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。
* 其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
* */
- 输出结果
my name is mmb
i am mmb,i want to go back home.
my name is mmb2
i am mmb2,i do not want to go back home.
动态代理实现
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。
- 编写一个委托类的接口,即静态代理的(DynamicSubject接口)
public interface DynamicSubject {
//需求一
void visit();
//需求二
void gohome();
//需求三四五六...
}
- 实现第一个真正的委托类,即静态代理的(RealDynamicSubject 类)
public class RealDynamicSubject implements DynamicSubject {
private String name = "mmb";
@Override
public void visit() {
System.out.println("my dynamic name is "+ name);
}
@Override
public void gohome() {
System.out.println("i am dynamic "+ name + ",i want to go home.");
}
}
- 实现第二个真正的委托类,即静态代理的(RealDynamicSubjec2t 类)
public class RealDynamicSubject2 implements DynamicSubject {
private String name = "mmb2";
@Override
public void visit() {
System.out.println("my dynamic name is "+ name);
}
@Override
public void gohome() {
System.out.println("i am dynamic "+ name + ",i don not want to go home.");
}
}
- 创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
return result;
}
public void setObject(Object object) {
this.object = object;
}
}
- 在测试类中,生成动态代理的对象。
public class testDynamic {
public static void main(String[] args){
//委托类RealDynamicSubject
DynamicSubject dynamicSubject = new RealDynamicSubject();
//代理类设置对象
DynamicProxy dynamicProxy = new DynamicProxy(dynamicSubject);
//委托类RealDynamicSubject的类加载器
ClassLoader classLoader = dynamicSubject.getClass().getClassLoader();
DynamicSubject subject = (DynamicSubject) Proxy.newProxyInstance(classLoader, new Class[]{DynamicSubject.class}, dynamicProxy);
subject.visit();
subject.gohome();
委托类RealDynamicSubject2
DynamicSubject dynamicSubject2 = new RealDynamicSubject2();
//代理类设置对象
dynamicProxy.setObject(dynamicSubject2);
//委托类RealDynamicSubject2的类加载器
ClassLoader classLoader2 = dynamicSubject2.getClass().getClassLoader();
DynamicSubject subject2 = (DynamicSubject) Proxy.newProxyInstance(classLoader2, new Class[]{DynamicSubject.class}, dynamicProxy);
subject2.visit();
subject2.gohome();
}
/** * 创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是: * ClassLoader loader表示当前使用到的appClassloader。 * Class<?>[] interfaces表示目标对象实现的一组接口。 * InvocationHandler h表示当前的InvocationHandler实现实例对象。 * */
- 输出结果
my dynamic name is mmb
i am dynamic mmb,i want to go home.
my dynamic name is mmb2
i am dynamic mmb2,i don not want to go home.
剖析动态反射 Proxy.newProxyInstance
- java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口、目标接口的类加载器以及InvocationHandler便可为目标接口生成代理类及代理对象。
// 方法 1: 该方法用于获取指定代理对象所关联的InvocationHandler
static InvocationHandler getInvocationHandler(Object proxy)
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
// 方法 3:该方法用于判断指定类是否是一个动态代理类
static boolean isProxyClass(Class cl)
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的;但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。
要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。在java中如何用程序去生成一个对象的代理对象呢,java在JDK1.5之后提供了一个"java.lang.reflect.Proxy"类,通过"Proxy"类提供的一个newProxyInstance方法用来创建一个对象的代理对象,如下所示:
写在末尾
公司的CTO写了一个模块的代码,由于是基于springBoot框架,用到了一部分注解:方法注解@NamedHandler;类注解@Name();这里的设计思路就是使用了动态反射代理。所以在此做个总结。