代理模式

概念

为其他类提供一种代理,以控制对这个类的访问

代理可以理解为助理,中介等,你想找直接领导只能找中间者,然后通过中间者去找领导

在面向对象系统中,有些对象由于(创建对象开销大、操作安全控制、需要进程外的访问)等一系列的问题,直接访问会带来很多麻烦,所以我们在访问此对象时加上一个此对象的访问层

角色

抽象角色:通过接口或抽象类声明真实角色实现的业务方法

代理角色:实现抽象角色,是真实角色的代理

真实角色:实现抽象角色,定义真是角色需要实现的业务逻辑,供代理角色调用

设计与实现

设计思想:汽车移动,计时,日志

一、没有代理

1、提供移动接口

package com.xjion.noproxy;

public interface Moveable {
	void move();
}

2、提供汽车

package com.xjion.noproxy;

import java.util.Random;

public class Car implements Moveable{

	@Override
	public void move() {
		System.out.println("汽车开始移动...");
		try {
			long startTime=System.currentTimeMillis();
			System.out.println("汽车移动中...");
			Thread.sleep(new Random().nextInt(2000));
			long endTime=System.currentTimeMillis();
			System.out.println("汽车运行结束,消耗时间为:"+(endTime-startTime)+"毫秒数!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

3、测试

package com.xjion.noproxy;

public class Test {
	public static void main(String[] args) {
		Moveable car=new Car();
		car.move();
	}
}

二、通过继承实现静态代理

1、移动接口

package com.xjion.staticproxy;

public interface Moveable {
	void move();
}

2、汽车

package com.xjion.staticproxy;

import java.util.Random;

public class Car implements Moveable{

	@Override
	public void move() {
		try {
			System.out.println("汽车移动中...");
			Thread.sleep(new Random().nextInt(2000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

3、代理添加日志,计时

package com.xjion.staticproxy;

/**
 * 通过继承的方式实现静态代理
 *
 */
public class LogTimeProxy extends Car{

	@Override
	public void move() {
		System.out.println("记录开始日志");
		System.out.println("汽车开始移动...");
		long startTime=System.currentTimeMillis();
		super.move();
		long endTime=System.currentTimeMillis();
		System.out.println("汽车停止移动,移动的时间为:"+(endTime-startTime)+"毫秒!");
		System.out.println("记录结束日志");
	}
	
}

4、测试

package com.xjion.staticproxy;

public class Test {
	public static void main(String[] args) {
		Moveable car=new LogTimeProxy();
		car.move();
	}
}

三、通过实现接口实现静态代理

1、提供移动接口,汽车

同上 ↑

2、提供计时功能

package com.xjion.staticproxy2;

public class TimeProxy implements Moveable{
	private Moveable moveable;
	
	public TimeProxy(Moveable moveable) {
		this.moveable = moveable;
	}


	@Override
	public void move() {
		System.out.println("汽车开始移动...");
		long startTime=System.currentTimeMillis();
		moveable.move();
		long endTime=System.currentTimeMillis();
		System.out.println("汽车停止移动,移动的时间为:"+(endTime-startTime)+"毫秒!");
	}
	
}

3、提供日志功能

package com.xjion.staticproxy2;

public class LogProxy implements Moveable{
	private Moveable moveable;
	
	public LogProxy(Moveable moveable) {
		this.moveable = moveable;
	}

	@Override
	public void move() {
		System.out.println("记录日志开始...");
		moveable.move();
		System.out.println("记录日志结束...");
	}
	
	
}

4、测试

package com.cdsxt.staticproxy2;

public class Test {
	public static void main(String[] args) {
        //计时并打印日志
		//Moveable car=new TimeProxy(new LogProxy(new Car()));
        //计时
		Moveable car=new TimeProxy(new Car());
		car.move();
		
		
	}
}

四、实现InvocationHandler接口实现动态代理

1、汽车和移动同上

2、飞机和飞行接口

package com.xjion.dynamicproxy;

public interface Flyable {
	void fly();
}
package com.xjion.dynamicproxy;

import java.util.Random;

public class Aircraft implements Flyable{

	@Override
	public void fly() {
		try {
			System.out.println("飞机在飞飞飞...");
			Thread.sleep(new Random().nextInt(2000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

3、代理

package com.xjion.dynamicproxy;

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

/**
 * 1)实现InvocationHandler,重写接口的方法
 * 2)获取代理对象 Proxy.newProxyInstance调用
 */
public class LogProxy implements InvocationHandler{
	private Object obj;
	
	//给被代理对象赋值
	public LogProxy(Object obj) {
		this.obj = obj;
	}
	/**
	 * proxy  代理对象
	 * method 被调用的方法
	 * args   实参列表
	 * return  调用方法之后的返回值
	 */ 
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("开始日志");
		//相当于之前的super.move()
		method.invoke(obj, args);
		System.out.println("结束日志");
		return null;
	}
	
	
}

4、测试

package com.xjion.dynamicproxy;

import java.lang.reflect.Proxy;

public class Test {
	public static void main(String[] args) {
//		Moveable car=(Moveable) Proxy.newProxyInstance(Car.class.getClassLoader(), 
//				Car.class.getInterfaces(), new LogProxy(new Car()));
//		car.move();
		
		
		Flyable aircraft=(Flyable) Proxy.newProxyInstance(Aircraft.class.getClassLoader(), 
				Aircraft.class.getInterfaces(), new LogProxy(new Aircraft()));
		
		aircraft.fly();
	}
}

注意:

Proxy.newProxyInstance()方法接受三个参数:

  • ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
  • Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
  • InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法

五、CGLIB代理

1、汽车移动

package com.xjion.cglibproxy;

import java.util.Random;

public class Car{

	public void move() {
		try {
			System.out.println("汽车移动中...");
			Thread.sleep(new Random().nextInt(2000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

2、飞机飞行

package com.xjion.cglibproxy;

import java.util.Random;

public class Aircraft{

	public void fly() {
		try {
			System.out.println("飞机在飞飞飞...");
			Thread.sleep(new Random().nextInt(2000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

3、代理

package com.xjion.cglibproxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TimeProxy implements MethodInterceptor{

	/**
	 * 提供返回代理对象的方法
	 */
	public Object getProxy(Class clazz){
		//创建代理对象工具实例
		Enhancer enhancer=new Enhancer();
		//设置被代理对象的反射对象
		enhancer.setSuperclass(clazz);
		//调用回调函数
		enhancer.setCallback(this);
		//返回代理对象
		return enhancer.create();
	}
	
	
	/**
	 * obj 被代理的对象
	 * method 被代理的方法
	 * args 调用方法的实参
	 * proxy 代理对象
	 * 
	 * 返回值是   调用方法后的返回值
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		long startTime=System.currentTimeMillis();
		//调用被代理的方法
		proxy.invokeSuper(obj, args);
		long endTime=System.currentTimeMillis();
		System.out.println("汽车运行结束,使用时间为"+(endTime-startTime)+"毫秒!");
		return null;
	}
}

4、测试

package com.xjion.cglibproxy;

import java.lang.reflect.Proxy;

public class Test {
	public static void main(String[] args) {
//		Car car=(Car) new TimeProxy().getProxy(Car.class);
//		car.move();
		
		
		Aircraft aircraft=(Aircraft) new TimeProxy().getProxy(Aircraft.class);
		aircraft.fly();
	}
}

 

总结:

两种静态代理:

1、可以在符合开闭原则的情况下对目标进行功能扩展

2、不易于管理,接口变实现类也会变

JDK动态代理:

1、减少开发任务

2、降低对接口的依赖,从而降低了耦合度

3、CHLIB创建动态代理对象性能低

4、创建对象花费时间少

CGLIB代理:

1、使用字节码技术

2、CHLIB创建动态代理对象性能高

3、创建对象花费时间多

4、适合创建单例对象

与装饰器模式相比

装饰器模式:

1、不改变接口动态扩展功能

2、将对象传递给Decorator的构造函数使用

3、增强自身的功能

代理模式:

1、提供代理对象,不改变接口控制对象的访问

2、创建真实对象的实例

3、让比尔去做一些和本身业务没有太多关系的职业

 

共同点

1、都是实现同一个接口,一个类包装另一个类

2、都是对类的方法进行扩展

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值