动态代理模式

1.意图

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

2.参与者

抽象角色:声明真实对象和代理对象的共同接口;

代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

3.模式结构

动态代理模式_第1张图片

Java在java.lang.reflect包下,定义了自己的代理。利用这个包下的类,我们可以在运行时动态地创建一个代理类,实现一个或多个接口。并将方法的调用转发到你所指定的类。因为实际代理是在运行时创建的,所以称为:动态代理。动态代理解决了静态代理代理类膨胀的问题.

Proxy :完全由java产生的,而且实现了完整的subject接口。提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类,我们经常使用的静态方式是:

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

该方法返回代理类的一个实例,返回后的代理类可以当作被代理类使用.


InvocationHandler: Proxy上的任何方法调用都会被传入此类,InvocationHandler控制对RealSubject的访问。
因为Java已经帮助我们创建了Proxy类,我们需要有办法告诉Proxy类你要做什么,我们不能像以前一样把代码写入到Proxy类中,因为Proxy类不是我们实现的。那么我们应该放在哪里?放在InvocationHandler类中,InvocationHandler类是响应代理的任何调用。我们可以吧InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。
被代理实例所实现的一个接口,内部只有一个invoke()方法,签名如下;

public Object invoke(Object proxy, Method method, Object[] args)
当代理的方法被调用的时候,代理就会把这个调用转发给InvocationHandler,也就会调用它的invoke()方法。在实际使用时,第一个参数proxy一般是指被代理类,method是被代理的方法,args为该方法的参数数组.

4.实现步骤

1.创建一个实现接口InvocationHandler的类,她必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法.

5.举例

例一

//定义一个抽象接口

public interface Foo
{
	void doAction();
}
//定义一个实现类
public class FooImpl implements Foo
{

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

}
//另一个实现类
public class FooImpl2 implements Foo
{
	public FooImpl2()
	{
		
	}
	@Override
	public void doAction()
	{
		// TODO Auto-generated method stub
		System.out.println("in FoolImpl2.doAction()");
	}

}

public class CommonInvocationHandler implements InvocationHandler
{
	//动态执行对象,需要回调的对象
	private Object target;
	//支持构造方法注入
	public CommonInvocationHandler()
	{
		
	}
	
	public CommonInvocationHandler(Object target)
	{
		setTarget(target);
	}
	
	
	public Object getTarget()
	{
		return target;
	}

	public void setTarget(Object target)
	{
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable
	{
		// TODO Auto-generated method stub
		System.out.println("before method");
		method.invoke(target, args);
		System.out.println("after method");
		return null;
	}
}

public class Test
{
	public static void main(String[] args)
	{
		CommonInvocationHandler commonInvocationHandler = new CommonInvocationHandler();
		
		commonInvocationHandler.setTarget(new FooImpl());
		Foo foo = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, commonInvocationHandler);
		foo.doAction();
		
		FooImpl2 fooImpl2 = new FooImpl2();
		commonInvocationHandler.setTarget(fooImpl2);
		Foo foo2 = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(), fooImpl2.getClass().getInterfaces(), commonInvocationHandler);
		foo2.doAction();
	}



例二:自己可以查看修改姓名性别,但是不能修改rate。他人可以查看姓名,性别以及修改rate,但是不能修改姓名性别。

//定义一个接口
public interface Person {     
         
    String getName();     
         
    String getGender();     
         
    void setName(String name);     
         
    void setGender(String gender);     
         
    void setRate(int rate);     
         
    int getRate();     
} 
//定义实现Person接口类
public class PersonImpl implements Person {     
String name;     
    
String gender;     
    
String interests;     
    
int rate;     
    
public String getName() {     
    return name;     
}     
    
public void setName(String name) {     
    this.name = name;     
}     
    
public String getGender() {     
    return gender;     
}     
    
public void setGender(String gender) {     
    this.gender = gender;     
}     
    
public String getInterests() {     
    return interests;     
}     
    
public void setInterests(String interests) {     
    this.interests = interests;     
}     
    
public int getRate() {     
    return rate;     
}     
    
public void setRate(int rate) {     
    this.rate = rate;     
}
//定义OwnerInvocationHandler类,表示如果为本人,则可以进行修改查看姓名性别
public class OwnerInvocationHandler implements InvocationHandler{     
         
    private Person personBean;     
         
    public OwnerInvocationHandler(Person personBean){     
        this.personBean = personBean;     
    }     
         
    @Override    
    public Object invoke(Object proxy, Method method, Object[] args)     
            throws IllegalAccessException {     
             
        try {     
            if(method.getName().startsWith("get")){//如果方法名为get,就调用person类内的get相应方法     
    
                return method.invoke(personBean, args);     
            }else if(method.getName().equals("setRate")){ // 如果方法是setRate,则抛出异常     
                throw new IllegalAccessException("access deny");     
            }else if(method.getName().startsWith("set")){  //如果为set,就调用person类内的set相应方法     
                return method.invoke(personBean, args);     
            }else {     
                System.out.println("non method invoke");     
            }     
        } catch (InvocationTargetException e) {     
            e.printStackTrace();     
        }     
        return null;      
             
    }     
         
}
//定义NonInvocationHandler类,表示如果不为本人,则可以进行查看姓名性别和修改rate
public class NonInvocationHandler implements InvocationHandler{     
    //     
    private Person person;     
         
    public NonInvocationHandler(Person person){     
        this.person = person;     
    }     
    
    @Override    
    public Object invoke(Object proxy, Method method, Object[] args)     
            throws Throwable {     
        if(method.getName().startsWith("setRate")){     
            return method.invoke(person, args);     
        }else if (method.getName().startsWith("get")){     
            return method.invoke(person, args);     
        } else {     
            System.out.println("non method invoke");     
            return null;     
        }     
    }     
         
} 
//测试类
public class MyDynamicProxy {     
    
public Person getOwnerPersonBeanProxy(Person person){ 
//	Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader()  
//              , new Class[]{Subject.class});  
//      Subject subject = (Subject)proxyClass.getConstructor(new Class[]{InvocationHandler.class})  
//              .newInstance(new Object[]{handler});  <span style="font-family: 宋体;">//InvocationHandler handler = new DynamicProxy(person);</span><span style="font-family: 宋体;">   </span>
    return (Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),      
            person.getClass().getInterfaces(), new OwnerInvocationHandler(person));     
}     
    
public Person getNonPersonBeanProxy(Person person){     
    return (Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),      
            person.getClass().getInterfaces(), new NonInvocationHandler(person));     
}     
    
public static void main(String[] args) {     
    MyDynamicProxy mdp = new MyDynamicProxy();     
    mdp.test();     
         
}     
    
public void test(){     
                //     
    Person person = getPersonBeanFromDB1();     
    Person personProxy = getOwnerPersonBeanProxy(person);     
    System.out.println(personProxy.getName());      
    try {     
        personProxy.setRate(2);     
    } catch (Exception e) {     
        System.out.println("can not setRate");     
    }     
                 //     
    Person person1 = getPersonBeanFromDB1();     
    Person personProxy2 = getNonPersonBeanProxy(person1);     
    System.out.println(personProxy2.getName());     
    personProxy2.setRate(2);     
    System.out.println(personProxy2.getRate());     
}     
    
private Person getPersonBeanFromDB1(){     
    Person pb = new PersonImpl();     
    pb.setName("remy");     
    pb.setGender("girl");     
    pb.setRate(1);     
    return pb;     
}

5.代理模式使用原因和应用方面

(1)授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.
(2)某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
     举例两个具体情况: 
     如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片.
     如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象.
     总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存. 所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系.
(3)现实中,Proxy应用范围很广,现在流行的分布计算方式RMI和Corba等都是Proxy模式的应用,Spring的AOP也是基于动态代理模式




你可能感兴趣的:(代理,模式)