代理设计模式:静态代理和动态代理的理解、实现与区别(优缺点)

一、代理设计模式

下载本文章演示案例工程代码
首先,要明确什么是代理。通俗的说,就是日常生活中的中介。比如你要租房子,找了中介,中介负责打理你的一切事务(找房、签约等),这些事务你都不用做,你就负责住房就可以。代理同理,如果你想访问一个目标对象,就得通过代理对象去访问,代理对象会进行一些操作后(验证、打印日志等)才让你访问目标对象,也可以在你访问对象后进行一些代理操作。代理可以实现在保持目标对象代码不变的情况下,对对象访问前后进行一些操作,简而言之,如下图所示,就是对目标对象的访问控制。代理可以分为静态代理和动态代理。
在这里插入图片描述

二、静态代理

(一)静态代理实现的条件

要想采用静态代理方式,需要具备以下条件:
1.目标类具有接口,并实现了其接口。
2.代理类也得实现目标类的接口,并有一个属性是目标类接口。
3.代理类的得有一个无参构造方法和一个构造方法,参数为目标类接口类型,用于接收目标对象赋值给代理类的目标类接口属性。
4.代理类必须实现接口的所有方法,并在在方法中访问目标类对象的方法,在访问之前和之后都可以进行一些代理操作。UML如下图所示:
在这里插入图片描述

(二)静态代理代码实现过程案例演示

1.创建目标类接口MassegeService。
package testspringAOP.proxy;
/**
 * @author CenterLogo
 *create date :2019年4月28日 下午6:36:14
 */
public interface MassegeService {
public void sendMessage1();
public void sendMessage2();
public void sendMessage3();
}
2.创建目标类MassegeServiceImpl并实现接口。
package testspringAOP.proxy;
/**
 * @author CenterLogo
 *create date :2019年4月28日 下午6:39:23
 */
public class MassegeServiceImpl implements MassegeService {
	/**
	 * 业务逻辑实现类(被代理类)
	 */
	public MassegeServiceImpl() {
		// TODO Auto-generated constructor stub
	}
	public void sendMessage1() {
		// TODO Auto-generated method stub
    System.out.println("hello maven");
	}

	public void sendMessage2() {
		// TODO Auto-generated method stub
		   System.out.println("hello Spring");
	}

	public void sendMessage3() {
		// TODO Auto-generated method stub
		System.out.println("hello mybatis");
	}
}
3.创建代理类staticProxy并实现目标对象的接口,写有参造方法。
package testspringAOP.proxy;
/**静态代理类
 * @author CenterLogo
 *create date :2019年4月28日 下午6:52:44
 */
public class staticProxy implements MassegeService {
	MassegeService ms;//引入接口
	protected staticProxy() {//将无参构造修饰为受保护的,一般项目分包处理,代理。同子类才能调用无参。
		
	}
	public staticProxy(MassegeService ms) {//有参构造,传入被代理实例(目标对象),使用代理。
		this.ms=ms;
	}
  public void validatorInfo(){  //服务方法,业务为逻辑处理
	System.out.println("完成数据验证操作。");
  }
	public void sendMessage1() {
     this.validatorInfo();    
		ms.sendMessage1();
	}
	public void sendMessage2() {
	
	     this.validatorInfo();    
			ms.sendMessage2();
	}
	public void sendMessage3() {
	     this.validatorInfo();    
			ms.sendMessage3();
	}
}
4.创建测试ProxyTest类通过代理访问目标类方法。
package testspringAOP.proxy;

/**
 * @author CenterLogo
 *create date :2019年4月28日 下午6:48:58
 */
public class ProxyTest {
	public ProxyTest() {
		// TODO Auto-generated constructor stub
	}
	 
	 public void testStatic(){
	 //通过传目标对象实例获取代理类,通过代理类对象访问目标对象实例方法。
		 MassegeService ms =new staticProxy(new  MassegeServiceImpl());
		 ms.sendMessage1();
		 ms.sendMessage2();
		 ms.sendMessage3();
	 }

	public static void main(String[] args) {
		// TODO Auto-generated method stub
       ProxyTest pt=new ProxyTest();
       pt.testStatic();
	}

}

测试成功结果为:

完成数据验证操作。
hello maven
完成数据验证操作。
hello Spring
完成数据验证操作。
hello mybatis

(三)静态代理的优缺点

1.优点
  • 静态代理对客户(测试类)隐藏了被代理类接口(目标类接口)的具体实现类,在一定程度上实现了解耦合,同时提高了安全性!
2.缺点
  • 静态代理类需要实现目标类(被代理类)的接口,并实现其方法,造成了代码的大量冗余。

  • 静态代理只能对某个固定接口的实现类进行代理服务,其灵活性不强。故一般大项目不会选择静态代理。

三、动态代理

(一)动态代理实现的条件

动态代理能够实现代理类无需和被代理类直接关联,但是动态代理类必须实现Invocation接口,并且实现invoke() 方法,在invoke()方法中需要完成两件事情:一是添加服务,二是调用业务逻辑方法。代理服务就是在代理类中的invoke中执行的。我们可以通过反射机制获取目标对象的加载类、接口,还有实现了Invocation接口的代理类传到Proxy.newProxyInstance(被代理类,被代理类接口,代理类)方法中获取到代理类的对象实例。

(二)动态代理代码实现过程案例演示

1.创建动态代理类DynamicProxy,实现Invocation接口,并实现invoke() 方法。并提供一个方法获取代理类实例,即bin(Object oj)方法。
package testspringAOP.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理类
 * @author CenterLogo
 *create date :2019年4月28日 下午7:32:18
 */
public class DynamicProxy implements InvocationHandler {
	private Object obj;
	public DynamicProxy() {	//无参构造
	}
     public Object bin(Object obj){//参数传入被代理对象,返回代理对象实例
    	 this.obj=obj;
    	 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);//代理中的invoke()方法在这Proxy.newProxyInstance()中执行
     }
     public void validatorInfo(){  //服务方法,业务为逻辑处理
    		System.out.println("完成数据验证操作。");
    	  }
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object obj=null;
		this.validatorInfo();
		obj=method.invoke(this.obj, args);
		return obj;
	}
}
2.创建被代理类即其接口,此次还是使用MassegeServiceImpl类和MassegeServiceImpl接口,代码详见静态代理。
3.创建测试类ProxyTest,测试动态代理实现。
package testspringAOP.proxy;
/**
 * @author CenterLogo
 *create date :2019年4月28日 下午6:48:58
 */
public class ProxyTest {
	public ProxyTest() {
		// TODO Auto-generated constructor stub
	}
	 public void testDynamic(){
		 MassegeService ms =(MassegeService) new DynamicProxy().bin(new MassegeServiceImpl());
		 ms.sendMessage1();
		 ms.sendMessage2();
		 ms.sendMessage3();
	 }
	public static void main(String[] args) {
		// TODO Auto-generated method stub
       ProxyTest pt=new ProxyTest();
       pt.testDynamic();
	}
}

测试成功结果为:

完成数据验证操作。
hello maven
完成数据验证操作。
hello Spring
完成数据验证操作。
hello mybatis

(三)动态代理的优缺点

1.优点
  • 动态代理实现了只需要将被代理对象作为参数传入代理类就可以获取代理类对象,从而实现类代理,具有较强的灵活性。
  • 动态代理的服务内容不需要像静态代理一样写在每个代码块中,只需要写在invoke()方法中即可,降低了代码的冗余度。
2.缺点
  • 动态代理类仍然需要实现接口。

一般大型项目都选择采用动态代理方式,如SpringAOP就采用了动态代理,有jdk动态代理和cglib动态代理。欲了解SpringAOP动态代理,请看《AOP动态代理声明式的3种配置方式过程与区别》。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值