设计模式学习系列--代理模式

代理模式

一、代理模式(为其他对象提供一种代理以便控制对这个对象的访问)


代理组成:调用者,统一的接口,真实对象,代理类
原理: 通过接口,实现这样一个过程,在调用真实对象的时候,调用者并不直接与真实对象打交道,而是通过一个代理者与真实对象通信,代理者能够负责真实对象的非业务逻辑,如日志管理、访问控制 、异常处理等,使得真实对象专注于业务逻辑的实现,不受非业务逻辑的干扰。

二、静态代理实现

自己静态定义代理类

2.1 统一接口

/**
 * 统一的接口
 * @author Administrator
 *
 */
public interface Subject {
	void request();
}

2.2 真实对象

/**
 * 真实对象
 * @author Administrator
 *
 */
public class RealSubject implements Subject {

	public void request() {
		System.out.println(" RealSubject excute request");
	}

}

2.3 代理对象

/**
 * 代理者
 * @author Administrator
 *
 */
public class Proxy implements Subject {
	
	private RealSubject realSubject;
	
	public Proxy(RealSubject realSubject){
		this.realSubject = realSubject;
	}
	
	public void request() {
		//植入的前置代码
		System.out.println("####before##");
		try {
			realSubject.request();//真实对象执行的方法
			System.out.println("###after##");
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("####exception###");
		}finally{
			//植入的后置逻辑
			System.out.println("###finally##");
		}
	}

}

2.4客户端调用

/**
 * 客户端
 * @author Administrator
 *
 */
public class Client {
	public static void main(String[] args) {
		Subject subject = new Proxy(new RealSubject());
		subject.request();
	}
}

2.5 运行结果


总结:如果在接口中添加方法进行功能扩展,代理类需要重复写对应接口的实现方法,增加重复性代码,而且不利于维护和扩展

三、JDK实现的动态代理

3.1 动态代理

不需要自己是实现代理类,利用JDK的API,在内存中自动生成代理类,源码探索:http://blog.csdn.net/shenbug/article/details/78960639

3.2 实现的要点

基于接口 InvoctionHandler实现动态代理,由 java.lang.reflect.Proxy实现代理类的创建

3.3 接口

/**
 * 统一的接口
 * @author Administrator
 *
 */
public interface Subject {
	void request();
}

3.4真实对象

/**
 * 真实对象
 * @author Administrator
 *
 */
public class RealSubject implements Subject {

	public void request() {
		System.out.println(" RealSubject excute request");
	}

}

3.5动态代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * JDK实现动态代理
 * @author Administrator
 *
 */
public class JdkProxy implements InvocationHandler{
	//目标对象
	private Object targetobject; 
	
	public JdkProxy(Object targetobject){
		this.targetobject = targetobject;
	}
	//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
	public Object newProxyInstance(){
		//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例    
        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器  
        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口  
        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法  
        //根据传入的目标返回一个代理对象  
		return Proxy.newProxyInstance(targetobject.getClass().getClassLoader(), 
				targetobject.getClass().getInterfaces(), this);
	}
	/**
	 * @param proxy 被代理的对象
	 * @param method 要调用的方法
	 * @param args  方法调用所需要的参数
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object res = null;
		try {
			 /*原对象方法调用前处理信息*/  
			System.out.println("start");
			//调用目标方法
			res = method.invoke(targetobject, args);
		} catch (Exception e) {
			e.printStackTrace();
			/*原对象方法调用异常处理信息*/  
			System.out.println("error");
		}finally{
			/*原对象方法调用前处理信息*/  
			System.out.println("success");
		}
		return res;
	}

}

3.6 客户端调用

public class Client1 {
	public static void main(String[] args) {
		//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
		JdkProxy jdkProxy = new JdkProxy(new RealSubject());
		Subject subject = (Subject) jdkProxy.newProxyInstance();
		subject.request();
	}
}

3.7 测试


四、cglib实现动态代理

4.1 实现原理

1:生成指定类对象的子类,也就是重写类中的业务函数。
2:执行回调函数,加入intercept()函数。
3:创建这个类的子类对象。
/**
 * cglib实现动态代理
 * @author Administrator
 *
 */
public class CglibProxy implements MethodInterceptor{
	
	//维护目标对象
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }
    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }
	/**
	 * 添加植入的代码
	 */
	public Object intercept(Object obj, Method arg1, Object[] arg2,
			MethodProxy proxy) throws Throwable {
		/*原对象方法调用前处理信息*/  
		System.out.println("####before####");
		Object result = null;
		try {
			//原对象方法调用
			result = proxy.invokeSuper(obj, arg2);
		} catch (Exception e) {
			// TODO: handle exception
			/*原对象方法调用异常处理信息*/ 
			System.out.println("#####exception#####");
		}finally{
			/*原对象方法调用后处理信息*/ 
			System.out.println("#####after####");
		}
		return result;
	}

}

4.2 客户端调用

public class Client1 {
	public static void main(String[] args) {
		//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
		JdkProxy jdkProxy = new JdkProxy(new RealSubject());
		Subject subject = (Subject) jdkProxy.newProxyInstance();
		subject.request();
	}
}

4.3 测试


五、jdk代理与cglib代理的对比


1.jdk基于接口实现代理,cglib基于继承的方式实现代理
2.cglib不能代理static、final修饰的类
3.jdk只能实现代理实现接口类的方法



 
   
  


猜你喜欢

转载自blog.csdn.net/shenbug/article/details/78965807