代理模式
原来的对象丢进代理类中,代理类会添加自己的属性和操作,如控制对象的访问,或者将原来的方法进行完善,如添加日志。这也是Spring aop的实现原理。
代理模式偏向于完善某个特定的方法,所以经常是要和被代理的真实角色实现同一个方法。对象的实例常常是代理类中进行创建。
1. 装饰者模式和代理模式的区别
装饰者模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰者模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
2. 静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类实现。
- 真实角色:被代理角色。
- 代理角色:代理真实的角色,代理真实角色后会做附属操作。
- 客户:访问代理对象的角色。
public class StaticProxy {
public static void main(String[] args) {
You you = new You(); // 你要结婚
WeddingCompany weddingCompany = new WeddingCompany(you);
weddingCompany.happyMarry();
}
}
interface Marry {
void happyMarry();
}
// 真实角色,你去结婚
class You implements Marry {
@Override
public void happyMarry() {
System.out.println("要结婚了,超开心");
}
}
// 代理角色,帮助你结婚
class WeddingCompany implements Marry {
// 代理谁-> 真实目标角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
before();
this.target.happyMarry(); // 这就是真实对象
after();
}
private void after() {
System.out.println("结婚后,收尾款");
}
private void before() {
System.out.println("结婚前,布置现场");
}
}
总结:
- 真实对象和代理对象都要实现同一个接口。
- 代理对象要代理真实角色。
好处:
- 代理对象可以做很多公共的业务,实现业务的分工。
- 真实对象专注做自己的业务。
- 公共业务发生扩展的时候,方便集中管理。
缺点:
静态代理中一个真实角色就会产生一个代理角色,开发效率低。
和实现Runnable接口创建线程作对比:
- Marry接口——>Runnable接口
- 实现Marry接口的You类——>实现Runnable接口的自己编写的类
- 实现Marry接口的WeddingCompany类——>实现Runnable接口的Thread类
Thead类实际上就是一个代理类。
3. 动态代理
动态代理就是通过反射完成代理的实现。
- 动态代理和静态代理的角色相同。
- 动态代理类是动态生成的。
- 动态代理的分类:基于接口的动态代理,基于类的动态代理。
- 基于接口--JDK动态代理
- 基于类:cglib
- Java字节码实现:javasist(JBoss)
- 动态代理需要用到的类:Proxy(代理)、InovationHandler(调用处理程序)。
将上面的静态代理转成动态代理模式
public class DynamicProxy {
public static void main(String[] args) {
You you = new You(); // 你要结婚
WeddingCompany weddingCompany = new WeddingCompany();
weddingCompany.setTarget(you);
Marry proxy = (Marry) weddingCompany.getProxy();
proxy.happyMarry();
}
}
interface Marry {
void happyMarry();
}
// 真实角色,你去结婚
class You implements Marry {
@Override
public void happyMarry() {
System.out.println("要结婚了,超开心");
}
}
class WeddingCompany implements InvocationHandler {
private Marry target;
public void setTarget(Marry target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object object = method.invoke(target, args);
after();
return object;
}
private void after() {
System.out.println("结婚后,收尾款");
}
private void before() {
System.out.println("结婚前,布置现场");
}
}
万能动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = method.invoke(proxy, args);
return object;
}
}
动态代理类中的invoke方法,可以做的事情比静态代理多很多(反射)。而且代码可以做到很简洁。
动态代理的好处:
- 静态代理类的好处都有。
- 一个动态代理类代理的是一个接口或者一个父类,一般就是对应的一类业务。
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。