Java 代理模式

     写一点代理模式的个人理解

     代理模式可以说是:本来由A去执行的方法,但是A不去执行,由B去代A执行。

     代理可分为静态代理和动态代理,静态代理中用代理类也实现了接口的方法。动态代理中用到了反射。

     先看一下静态代理的草图:

  

Real和代理类Proxy同时实现了接口,在客户端调用时直接调用代理类即可,然后代理类中的Real对象再去调用真正实现的方法,这样便形成了代理,达到了使用代理的目的。

优点是:代理类将真实类的方法封装了起来,可以在调用真正实现方法时添加前置和后置方法。

缺点是:实现一个代理类会多出很多的代码,造成了冗余,而且这个代理类必须事先存在。

不写这个代码了。

  动态代理实现,先贴代码:

package Proxy;
import java.lang.reflect.*;

interface BusinessFoo{
	void foo();
} 
interface BusinessBar{
	String bar(String message);
}

class BusinessFooImpl implements BusinessFoo{

	@Override
	public void foo() {
		// TODO Auto-generated method stub
		System.out.println("BusinessFooImpl.foo()");
	}
}

class BusinessBaeImpl implements BusinessBar{

	@Override
	public String bar(String message) {
		// TODO Auto-generated method stub
		System.out.println("BusinessBarImpl.bar()");
		return message;
	}
	
}

class BusinessImplProxy implements InvocationHandler{

	private Object obj;   //obj是真正实现方法的对象
	BusinessImplProxy(){
		
	}
	BusinessImplProxy(Object obj){
		this.obj = obj;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		Object result = null;
		doBefore();
		result = method.invoke(obj, args);  //去调用真正的方法 foo()和bar()
		doAfter();
		return result;
	}
	public  void  doBefore() {
		System.out.println("Do something before Business logic");
	}
	public void doAfter() {
		System.out.println("Do something after Business logic");
	}
	public static Object factory(Object obj){
		Class<?> cls = obj.getClass();   
		System.out.println("cls.getClass is:"+cls.getClass());
		System.out.println("obj的类型是:"+obj.getClass().getName());
		Class<?>[] interfaces  = cls.getInterfaces();
		for(Class<?> itf : interfaces)
		{
			System.out.println(itf.getName());
		}
		System.out.println("ClassLoader is: "+cls.getClassLoader());  //ClassLoader is: sun.misc.Launcher$AppClassLoader@1372a1a
		return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), 
				new BusinessImplProxy(obj));         //返回一个代理对象  getClassLoader()表示该运行时类 //的加载,getInterfaces()是得到运行时类的实现接口,动态代理只是实现了接口,没有实现抽象类,new BusinessImplProxy(obj)则表示真正对///象
	}
}

public class DymnaticProxy {

	
	public static void main(String[] args) {
	//	 TODO Auto-generated method stub
		BusinessFooImpl bFooImpl = new BusinessFooImpl();
		BusinessFoo bf = (BusinessFoo)BusinessImplProxy.factory(bFooImpl);  
		bf.foo();  //去调用invoke();这一块调用哪个真正的方法,invoke中则去调用哪个
		System.out.println();
		
		BusinessBaeImpl bbar = new BusinessBaeImpl();
		BusinessBar bb = (BusinessBar)BusinessImplProxy.factory(bbar);
		String messageString  = bb.bar("Hello world"); //去调用invoke();
		System.out.println(messageString);

	}

}


代理类必须得实现InvocationHandle的接口,该接口中有一个invoke方法。

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法由程序员来指定参数动态返回需要的代理类,而invoke(Object proxy,Method method, Object[] args) 方法则是由JVM在运行时动态调用的。当执行“bb.bar("Hello,World");”方法时,JVM动态指派“调用处理器”,向外层invoke传递参数,并调用method.invoke(obj,args)真正执行!


BusinessImplProxy.Factory静态方法用来动态生成代理类(“代理角色”),在运行时根据不同的业务逻辑接口BusinessFoo和BusinessBar,在运行时分别动态生成了代理角色。“抽象角色”、“代理角色”以及调用处理器(实现InvocationHandler接口的类)这三者都可以改变,所以说JAVA的动态代理十分强大。


在动态代理使用过程中有几个重要的类:Proxy,Method,Class<?>. 还有这个InvocationHandler接口。

Proxy类只能从子类为InvocationHandler构造一个Proxy实例,Proxy类的无参构造函数为私有,禁止实例化。

 /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

    /**
     * Prohibits instantiation.
     */
    private Proxy() {
    }

    /**
     * Constructs a new <code>Proxy</code> instance from a subclass
     * (typically, a dynamic proxy class) with the specified value
     * for its invocation handler.
     *
     * @param   h the invocation handler for this proxy instance
     */
    protected Proxy(InvocationHandler h) {
	this.h = h;
    }


<span style="font-size:14px;">
</span>

获得代理类的方法:
 public static Class<?> getProxyClass(ClassLoader loader, 
                                         Class<?>... interfaces)
	throws IllegalArgumentException
通过ClassLoader 和 Interfaces就可以获得一个运行时的代理类的Class对象。

newProxyInstance()这个静态方法的作用是获得代理类的实例:

 public static Object newProxyInstance(ClassLoader loader,
					  Class<?>[] interfaces,
					  InvocationHandler h)
	throws IllegalArgumentException
    {
	if (h == null) {
	    throw new NullPointerException();
	}

	/*
	 * Look up or generate the designated proxy class.
	 */
	Class cl = getProxyClass(loader, interfaces);

	/*
	 * Invoke its constructor with the designated invocation handler.
	 */
	try {
	    Constructor cons = cl.getConstructor(constructorParams);
	    return (Object) cons.newInstance(new Object[] { h });
	} catch (NoSuchMethodException e) {
	    throw new InternalError(e.toString());
	} catch (IllegalAccessException e) {
	    throw new InternalError(e.toString());
	} catch (InstantiationException e) {
	    throw new InternalError(e.toString());
	} catch (InvocationTargetException e) {
	    throw new InternalError(e.toString());
	}
    }
通过上面的getProxyClass方法获得代理类的运行时对象,再经过反射获得构造器,然后构造一个新实例。
该方法返回的是一个Object类型的对象,进行强制类型转换后就可以变成要使用的类型了。

再看上面调用实现接口的方法:bf.foo();
这句调用的是InvocationHandler中的方法:
public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {

该方法有三个参数:第三个参数是一个Object类型的数组,它传递的是foo()的参数,第二个参数是Method类的对象,这个类要关注一下。

Method类封装了一些方法,比如获得方法的名称,修饰符,返回类型,异常等等,这个类和Class类关系很大,通常用于反射,可以通过Class对象获取类运行时方法信息:getMothods(),然后返回的就是Method类型对象。在Class类中其他的也一样,可以通过方法getConstructor()获得构造器,返回的是一个Constructor对象,这些都有相应的类型。然后再调用相应类中的方法。
 Method类中有一个invoke():
ublic Object invoke(Object obj, Object... args)
	throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
在上面的例子中调用before()后,就调用的是这个方法,该方法的第一个参数是一个对象,第二个参数表示方法的参数,但是没有该方法,实际上调用InvocationHandler接口中的invoke方法的时候,Method的对象就是传递的foo这个方法,而现在的对象则表示 bf,写法则和普通的写法不同,用到了反射。


还有Class<?>这个类,这个是反射用到的类,获取类的运行时对象,然后可以通过 构造实例访问类的方法,属性等等,也可以获得类的所有信息,这些信息都是在运行时获得的,有时候在编译的时候无法获得要运行哪个类,这时候用反射就和知道要运行哪个类一样的去获得该类的信息。该类中返回的很多对象都是另一些类型的,这些和反射联系的很紧密,所以有时候也需要看看。

InvocationHandler这个接口里就只有一个方法:
 public Object invoke(Object proxy, Method method, Object[] args)
	throws Throwable;
实现该接口就相当于是代理类。


先写这些



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间充当中介,以便于客户端访问目标对象时,可以在不改变目标对象的情况下添加一些额外的功能,比如安全性、远程访问、缓存等。 在Java中,代理模式可以通过两种方式实现:静态代理和动态代理。静态代理需要手动编写代理类,而动态代理可以在运行时通过反射机制动态生成代理类,更加灵活。 举个例子,假设我们有一个接口`Subject`,其中定义了一些方法。我们希望在调用这些方法时,增加一些额外的日志记录功能。我们可以编写一个代理类`SubjectProxy`,在代理类中实现接口方法并调用目标对象的方法,同时在方法前后添加日志记录的代码。客户端则通过代理类访问目标对象。 静态代理示例代码如下: ```java public interface Subject { void doSomething(); } public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something."); } } public class SubjectProxy implements Subject { private Subject realSubject; public SubjectProxy(Subject realSubject) { this.realSubject = realSubject; } @Override public void doSomething() { System.out.println("Before do something."); realSubject.doSomething(); System.out.println("After do something."); } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); Subject subjectProxy = new SubjectProxy(realSubject); subjectProxy.doSomething(); } } ``` 动态代理示例代码如下: ```java public class SubjectHandler implements InvocationHandler { private Object target; public SubjectHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before " + method.getName()); Object result = method.invoke(target, args); System.out.println("After " + method.getName()); return result; } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); InvocationHandler handler = new SubjectHandler(realSubject); Subject subjectProxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); subjectProxy.doSomething(); } } ``` 无论是静态代理还是动态代理代理模式都可以在不改变目标对象的情况下,为其添加额外的功能,提高代码的可复用性和灵活性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值