Java中的静态代理和动态代理

Java中使用代理的作用是对目标对象的增强,在实际中我们可以在执行目标方法前后进行一些必要的处理。

1.静态代理

静态代理比较容易理解,我们直接给出例子。比如我们的目标方法是request方法,但是我们希望在每次调用request方法前都进行处理,如打印日志,那么久需要使用代理来处理。

接口

public interface Subject{
    public void request();
}

目标类 

class SubjectImpl implements Subject{
  public void request(){
      System.out.println("I am dealing the request.");
  }
}

静态代理类

在静态代理类中我们接受实际的目标对象,并且在目标方法前后可以进行处理。

class StaticProxy implements Subject{
	//实际目标对象
    private Subject subject;
    
    public StaticProxy(Subject subject){
        this.subject = subject;
    }
    
    public void request(){
        System.out.println("PreProcess");
        subject.request();
        System.out.println("PostProcess");
    }
}

测试方法

在我们调用p.request()方法的时候则会打印出目标方法前后的信息

public class StaticProxyDemo {
    public static void main(String args[]){
    	//创建实际对象
        SubjectImpl subject = new SubjectImpl();
        
        //把实际对象封装到代理对象中
        StaticProxy p = new StaticProxy(subject);
        p.request();
    }
}

总结:静态代理的优缺点很明显,优点是代码简单,缺点是当目标对象有多个方法时,我们要对每个方法都进行处理,因此会非常繁琐。

2.动态代理

动态代理克服了静态代理的缺点,在动态代理中,目标对象的方法每次被调用都进行动态拦截。

简单解释一下下面的图:客户端每次调用都是代理对象的方法,不可能直接调用目标对象的方法,所有的调用方法都会被拦截下来,转发给代理处理器的invoke方法进行处理,在代理处理器的invoke方法中我们可以判定该方法是什么方法,有什么参数。最后再调用目标对象的真实方法来进行工作,真实方法执行结束以后,一路返回执行结果。

下面举例

接口和目标类与静态代理的相同

接口

public interface Subject {
	public void request();

}

目标类

public class SubjectImpl implements Subject {

	@Override
	public void request() {
		System.out.println("I am dealing the request.");
	}
}

代理处理器 

/*
 * 代理处理器,实现了InvocationHandler接口
 * */
public class ProxyHandler implements InvocationHandler {
	//持有目标对象的句柄
	private Subject subject;
	
	public ProxyHandler(Subject subject){
		this.subject = subject;
	}

	/*
	 * invoke()方法
	 * 此方法在代理对象调用任何一个方法时都会被调用
	 * 
	 * 第一个参数:proxy 代理对象
	 * 第二个参数:method 反射里面的Method类,查看具体调用哪个方法
	 * 第三个参数:args 具体的形参
	 * */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//输出代理类的名字
		System.out.println(proxy.getClass().getName());//代理对象所属的类是虚拟机自动生成的
		
		//定义预处理工作,当然也可以根据method的不同进行不同的预处理工作
		System.out.println("=========before========");
		//调用真实的目标对象来进行工作
		Object result = method.invoke(subject, args);
		System.out.println("=========before========");
		return result;//返回结果
	}

}

测试类 

//动态代理模式
public class TestDynamicProxy {
	public static void main(String[] args) {
		//1.创建目标对象
		final Subject subject = new SubjectImpl();
		
		//2.创建代理处理器对象
		ProxyHandler proxyHandler = new ProxyHandler(subject);
		
		//3.动态生成代理对象
		Subject proxySubject = (Subject) Proxy.newProxyInstance(
				subject.getClass().getClassLoader(), //类加载器
				subject.getClass().getInterfaces(), //具体的接口
				proxyHandler);	//代理对象需要代理处理器对象,代理处理器重写了invoke方法	

		//4.客户端通过代理对象调用方法,本次调用将自动地被代理处理器的invoke方法接收
		proxySubject.request();
		
		System.out.println(proxySubject.getClass().getName());
	}

}

测试结果:

com.sun.proxy.$Proxy0是代理对象所属的类,它是由虚拟机自动生成的。

对代理处理器 的理解:

代理处理器持有目标对象的句柄,并实现InvocationHandler接口

  • 主要是实现了invoke方法
  • 所有的代理对象方法调用,都会转发到invoke方法来
  • invoke的形参method,就是指代理对象方法的调用
  • 在invoke内部,可以根据method,使用目标对象不同的方法来响应请求
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值