定义:为其他对象提供一种代理(中介),以控制这个对象的访问。对这个对象进行访问控制的一个原因是为了只有我们确实需要这个对象时才对它进行创建和初始化。
使用场景:
1、延迟加载。如果一个对象并不是在任何场景都需要,且这个对象的创建需要消耗不少资源。
2、对原有对象方法的增强。这些加强可能是一些日志操作,基于设计模式开闭原则的考虑,这些加强不可能放到原有真实类里面,所以就新增了一个代理类。如Spring的AOP主要就是用了动态代理。
结构:
抽象主题角色(Subject):一个接口,该接口是真实对象和它的代理共同拥有。
真实主题角色(RealSubject):实现抽象主题接口的类。
代理角色(Proxy):该类实现了抽象主题接口,且拥有真实主题类的引用,可以操作真实主题类。
分类:
这里以按照代理的创建时期,代理类主要分为静态代理和动态代理两种。
静态代理:由程序员自行创建代理类,在运行前已经完成编译。
动态代理:在程序运行时,运用反射机制动态创建。无需程序员手工编写它的源代码。
静态代理的实现:
1、定义业务接口;
2、创建真实类,实现业务接口;
3、创建代理类,引用真实类,同时实现接口。
下面用java实现一个小Demo
接口定义
public interface Buick {
void produce();
}
真实类实现
public class BuickImpl implements Buick{
public void produce(){
System.out.println("produce Buick!");
}
}
创建静态代理类
/**
* 静态代理
* 接口更新了,需要重新修改实现类和代理类
* @author JeffXu
* @since 2016-11-24
*/
public class BuickProxy implements Buick{
private BuickImpl buickImpl;
public BuickProxy(BuickImpl buickImpl){
this.buickImpl = buickImpl;
}
public void produce(){
before();
this.buickImpl.produce();
after();
}
private void before(){
System.out.println("before");
}
private void after(){
System.out.println("after");
}
}
静态代理的弊端:
如果有多个接口,就会对应有多个的Proxy代理类。导致系统出现过多的代理类,有可能产生过多的重复代码。
动态代理的实现:
动态代理又分为JDK代理和cglib动态代理。使用JDK代理的前提是必须要有接口,如果没有定义接口,那就只能采用cglib动态代理的创建模式。
这里仅说明JDK的代理。实现步骤大体为:
1、定义业务接口;
2、创建真实类,实现业务接口;
3、创建动态代理类。
/**
* JDK动态代理
* 不需要写代理类,直接通过接口可以输出一个代理类。
* 如果没有接口的类,不能实现JDK动态代理。
* 这种情况下就得考虑CGLIB代理
* @author Jeff Xu
* @since 2016-11-24
*/
public class DynamicProxy implements InvocationHandler{
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
@SuppressWarnings("unchecked")
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
private void before(){
System.out.println("before");
}
private void after(){
System.out.println("after");
}
public static void main(String[] args) {
Buick buick = new BuickImpl();
DynamicProxy dynamicProxy = new DynamicProxy(buick);
Buick buickProxy = dynamicProxy.getProxy();
buickProxy.produce();
}
}