Java设计模式——静态和动态代理

代理的概念

代理提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。

************************************************

静态代理

目标对象实现的接口

interface Operation{
    void download();
}

目标对象实现类

class RealObject implements Operation{
    @Override
    public void download() {
        System.out.println("执行业务逻辑...");
    }
}

代理类:

通过实现与目标对象相同的接口
并维护一个代理对象,通过构造器传入实际目标对象并赋值
执行代理对象实现的接口方法,实现对目标对象实现的干预

class ProxyObject implements Operation{
    private Operation operation;
    public ProxyObject(Operation operation) {
        this.operation = operation;
    }
    @Override
    public void download() {
	    System.out.println("前拦截...");
            operation.download();//通过代理来调用实际对象的方法
            System.out.println("后拦截...");     
    }
}

主类

public class TestProxy {
  public static void main(String[] args) {
	Operation operation = new ProxyObject(new RealObject());//把实际对象传入代理
	operation.download();
  }
}

静态优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。

***************************************************

动态代理:

动态的在内存中构建代理对象(需要我们制定要代理的目标对象实现的接口类型),即利用JDK的API生成指定接口的对象,也称之为JDK代理或者接口代理。

public class ProxyFactory {
    private Object targetObject; 
    public ProxyFactory(Object targetObject) {
        this.targetObject = targetObject;
    }
public Object getProxyInstance(){
  return Proxy.newProxyInstance(
	targetObject.getClass().getClassLoader(), //和目标对象的类加载器保持一致
	targetObject.getClass().getInterfaces(), //目标对象实现的接口,因为需要根据接口动态生成对象
	new InvocationHandler() { //InvocationHandler:事件处理器,即对目标对象方法的执行			 
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			System.out.println("前拦截...");				 
			Object result = method.invoke(proxy, args);				 
			System.out.println("后拦截...");
			return result;
		}
	  });
    }
}

指定的接口在系统运行期间动态的生成代理对象。
实现主要由 java.lang.reflect.Proxy 类和java.lang.reflect.InvocationHandler接口。 
动态代理的缺点:动态代理只能对实现了相应Interface的类使用,如果某个类没有实现任何的Interface,就无法使用动态代理对其产生相应的代理对象! 
因此:在默认情况下,如果Spring AOP发现目标实现了相应的Interface,则采用动态代理为其生成代理对象实例;
而如果目标对象没有实现任何的Interface,Spring AOP会尝试使用CGLIB动态字节码生成类库,为目标对象生成代理对象实例!

CGLIB动态字节码生成

CGLIB扩展对象行为的原理是:对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为,只要将横切逻辑的实现放到子类中,然后让系统使用扩展后的目标对象的子类,就可以达到与代理模式相同的效果了。 相比于动态代理,CGLIB的优势就是,可以为没有实现任何接口的类进行扩展。

public class Requestable {  
  public void request() {  
     System.out.println("requestable without implementint any interface");  
  }  
}  

要对该类进行继承扩展,所以我们要使用CGLIB类库,
实现一个net.sf.cglib.proxy.Callback,或者使用net.sf.cglib.proxy.MethodInterceptor(继承自Callback)

import java.lang.reflect.Method;  
import org.joda.time.TimeOfDay;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  

public class RequestCallback implements MethodInterceptor {  
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
        if(method.getName().equals("request")) {  
            System.out.println("你调用了request方法")
            return proxy.invokeSuper(object, args);  
        }  
        return null;  
    }  
} 

我们使用MethodInterceptor为request方法实现了对request请求进行控制的逻辑 
然后我们现在通过Enhancer为目标对象动态生成一个子类,将RequestCallback的横切逻辑附加到该子类中:

import net.sf.cglib.proxy.Enhancer;  

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(Requestable.class);
        //设置Callback
        enhancer.setCallback(new RequestCallback());
        Requestable proxy = (Requestable) enhancer.create();
        proxy.request();
    }
}

缺点:使用 CGLIB 对类进行扩展的唯一限制就是 无法对 final 方法进行覆写

动态代理、动态字节码生成:就是 Spring AOP 所使用的核心技术,也就是 Spring AOP 的Weaving And Weaver 的实现原理了。

猜你喜欢

转载自blog.csdn.net/weixin_42679286/article/details/86634873
今日推荐