软件设计模式-代理模式

阅读数:88 评论数:0

跳转到新版页面

分类

架构学

正文

一、代理模式

为另一个对象提供一个替身或占位符控制对这个对象的访问。被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。

与适配器模式的区别,适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。与装饰者模式的区别,装饰者为了增强功能,代理模式是为了加以控制。

静态代理是在程序运行前就已经存在代理类的字节码文件
动态代理在内存中构建,动态生成类字节码,并加载到JVM中。Spring AOP底层,就是动态代理模式的实现。很多框架的RPC调用也是使用的动态代理模式。

二、静态代理

静态代理就是程序员在编写代码的时候就已经把代理类的源码写好了,编译后就会生成.class文件(即字节码文件)。

1、示例

// person接口
public interface Person {

	//租房
	public void rentHouse();
}
// 实现上述接口

public class Renter implements Person{

	@Override
	public void rentHouse() {
		System.out.println("租客租房成功!");
		
	}

}
// 代理类
public class RenterProxy implements Person{
	private Person renter;
	public RenterProxy(Person renter){
		this.renter = renter;
	}
	@Override
	public void rentHouse() {
		System.out.println("中介找房东租房,转租给租客!");
		renter.rentHouse();
		System.out.println("中介给租客钥匙,租客入住!");
		
	}

}

三、Java动态代理

Java动态代理类位于java.lang.reflect包下,InvocationHandler接口和Proxy类是核心

1、InvocationHandler接口

该接口中仅定义了一个方法

Object:invoke(Object obj,Method method,Object[] args)

在实际使用时,第一个参数obj一般是指代理类method是被代理的方法args为该方法的参数数组。这个抽象方法在代理类中动态实现。

2、Proxy类

该类即为动态代理类。

(1)Protected Proxy(InvocationHandler h)

构造函数,估计用于给内部的h赋值。

(2)Static Class getProxyClass(ClassLoader loader, Class[] interfaces)

获得一个代理类,其中loader是类装载器,interfaces是真正拥有的全部接口的数组。

(3)Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

返回代理类的一个实例,返回后的代理类可以当作被代理类使用。

3、使用步骤:

(1)创建一个实现接口InvocationHandler的类,自定义处理逻辑。

(2)通过Proxy的静态方法newProxyInstance创建一个代理。

(3)通过代理调用方法。

4、示例

(1)首先定义一个Person接口

public interface Person {

	//租房
	public void rentHouse();
}

(2)创建被代理的类

public class Renter implements Person{

	@Override
	public void rentHouse() {
		System.out.println("租客租房成功!");
		
	}

}

(3)创建RenterInvocationHandler类,这个类实现了InvocationHandler接口,并持有一个被代理类的对象。

public class RenterInvocationHandler<T> implements InvocationHandler{
	//被代理类的对象
	private T target;
	
	public RenterInvocationHandler(T target){
		this.target = target;
	}

	/**
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//代理过程中插入其他操作
		System.out.println("租客和中介交流");
		Object result = method.invoke(target, args);
		return result;
	}

}

(4)创建动态代理对象

public class ProxyTest {

	public static void main(String[] args) {

		//创建被代理的实例对象
		Person renter = new Renter();
		//创建InvocationHandler对象
		InvocationHandler renterHandler = new RenterInvocationHandler<Person>(renter);
		
		
		//创建代理对象,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
		Person renterProxy = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class}, renterHandler);
		renterProxy.rentHouse();
		
		//也可以使用下面的方式创建代理类对象,Proxy.newProxyInstance其实就是对下面代码的封装
		/*try {
			//使用Proxy类的getProxyClass静态方法生成一个动态代理类renterProxy 
			Class<?> renterProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class});
			//获取代理类renterProxy的构造器,参数为InvocationHandler
			Constructor<?> constructor = renterProxyClass.getConstructor(InvocationHandler.class);
			//使用构造器创建一个代理类实例对象
			Person renterProxy = (Person)constructor.newInstance(renterHandler);
			renterProxy.rentHouse();
			//
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
	}

}

四、CGLIB动态代理

jdk的动态代理需要被代理的类实现接口,如果被代理类没有实现接口,可以使用cglib代理。

cglib代理也叫作子类代理,它通过在内存中构建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,然后加入自己的需要操作,因为使用的是继承的方式,所以不能代理final类。

Spring-core中已经包含了cglib功能。

1、示例

(1)创建被代理类UserService

public class UserService {
	
	public void getName(){
		System.out.println("张三!");
	}

}

(2)创建代理工厂类ProxyFactory

public class ProxyFactory<T> implements MethodInterceptor {

	private T target;

	public ProxyFactory(T target) {
		this.target = target;
	}

	// 创建代理对象

	public Object getProxyInstance() {

		// 1.cglib工具类
		Enhancer en = new Enhancer();
		// 2.设置父类
		en.setSuperclass(this.target.getClass());
		// 3.设置回调函数
		en.setCallback(this);

		return en.create();
	}

   //拦截方法
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		System.out.println("开始事务...");

		// 执行目标对象的方法
		Object result = method.invoke(target, args);

		System.out.println("提交事务...");
		return result;
	}

}



相关推荐

策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。 设计原则:

观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 设计原则:</st

装饰者模式:动态将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。 设计原则:类应该对扩展

设计原则:要依赖抽象,不要依赖具体类。 这个原则听起来很像是“针对接口编程,不针对实现编程”,然而这里更强调“抽象”,不能让高层组件依赖底层组件,而且,不管高层或低层组件,“两者”应该依赖于抽象。 一

一、概述 单件模式:确保一个类只有一个实例,并提供一个全局访问点。对于频繁使用的对象,特别是重量级对象,可以省略创建对象所花费的时间,同时降低GC压力。 采用私有构造器。Spring容器中的Bean默

一、概述 命令模式:将动作的请求者从动作的执行者中解耦。 发起请求的对象是调用者,调用者只要调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何工作的。 命

一、概述 适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。 以上是对象适配器的图。 以上是类适配器的图。

外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 适配器是包装一个类,而外观模式是包装多个

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。 算法内的步骤不要切割的太细,否则会较没有弹性。 钩子是

迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各