Java动态代理(dynamic proxy)

什么是代理

代理:代理对象主要用来拦截目标业务对象(被代理对象)的访问。
A:代理对象要持有真实业务对象。(通过构造函数接收业务对象,并用成员变量记录)
B:代理对象要和真实业务对象,具备相同的行为方法(实现相同接口)
C:代理对象拦截对真实对象的访问,可以修改访问的参数、返回值,甚至拦截访问
代理模式与装饰模式区别
A:代理模式侧重与拦截,装饰模式侧重与加强
B:Java中自带的代理中,只能对接口进行代理。装饰只需要与被装饰类有共同父类。

举个栗子

定义person接口:

public interface Person {	
        public void buyMac(double money);
	public void takeSubWay(double money);	
	public void atHome();
}

实现类Student:

public class Student implements Person {
	@Override
	public void buyMac(double money) {
		System.out.println("学生买了个mac!");
		System.out.println("学生花了" + money + "RMB");
	}
	@Override
	public void takeSubWay(double money) {
		System.out.println("学生乘坐地铁!");
		System.out.println("学生了" + money + "RMB");
	}
	@Override
	public void atHome() {
		System.out.println("学生到家了好好休息");
	}
}

写一个代理类HuangSir:

代理类同时实现person接口,持有业务对象Student,构造函数添加Student。重写Student中的方法。

public class HuangSir implements Person {
	// 持有真实业务对象
	private Student student;
	// 接收真实业务对象
	public HuangSir(Student student) {
		this.student = student;
	}
	@Override
	public void buyMac(double money) {
		// 做一个拦截
		if (money < 5000) {
			System.out.println("没钱了,买不起!");
			return;
		}
		System.out.println("使用学生卡,优惠了" + money * 0.1 + "元");
		student.buyMac(money * 0.9);
	}
	@Override
	public void takeSubWay(double money) {
		// 做一个拦截
		if (money < 50) {
			System.out.println("没钱了,做不起地铁!");
			return;
		}
		student.takeSubWay(money);
	}
	@Override
	public void atHome() {
		System.out.println("到了楼下!");
		student.atHome();
	}
}

测试类:

public static void main(String[] args) {
        DynamicProxy2 dynamicProxy2 = new DynamicProxy2();
	Person p = (Person)dynamicProxy2.getDynamicProxy();
	// 访问方法
	p.buyMac(5000);
	System.out.println("---华丽的分界线---");
	p.takeSubWay(10);
	System.out.println("---华丽的分界线---");
	p.atHome();
}

什么是动态代理

动态代理利用Java的反射技术,在运行时创建一个实现某些给定接口的代理类其实例,代理的对象是接口;

动态代理的作用:

1、可以解决特定问题:一个接口的实现在编译时无法知道,需要在运行时才能实现;

2、实现某些设计模式:适配器或修饰器;

3、面向切面编程:SpringAOP

动态代理在程序运行过程中产生的一个代理对象;
在程序运行的过程中,动态在内存中生成一个类,代理需要被代理的目标对象,并且生成这个代理类的对象。

public static void main(String[] args) {
	// 创建被代理对象
	final Student s = new Student();
	// 先准备动态代理的三大参数
	// 被代理类的类加载器
	ClassLoader loader = s.getClass().getClassLoader();
	// 被代理对象的接口的Class对象数组
	Class<?>[] interfaces = s.getClass().getInterfaces();
	// 调用处理器
	InvocationHandler h = new InvocationHandler(){
	        // 当我们调用代理对象的功能时,代理对象,其实都来调用了处理器中的invoke功能
		// 因此,我们需要在invoke中写拦截的逻辑!
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			// Object proxy : 是代理对象本身
			// Method method :当前正在被调用的真实方法的对象
			// Object[] args : 当前正在被调用的真实方法的真实参数
			String name = method.getName();
			// 判断方法的名称,做出不同的拦截逻辑
			if( "buyMac".equals(name)){
				double money = (double) args[0];
				if (money < 5000) {
					System.out.println("没钱了,买不起!");
					return null;
				}
				System.out.println("使用学生卡,优惠了" + money * 0.1 + "元")
				return method.invoke(s, money * 0.9);
			}
			if( "takeSubWay".equals(name)){
			double money = (double) args[0];
			if (money < 50) {
				System.out.println("没钱了,做不起地铁!");
				return null;
			}
		}
		return method.invoke(s, args);
		}
        };
        Person p = (Person) Proxy.newProxyInstance(loader, interfaces, h);
        // 访问方法
	p.buyMac(5000);
	System.out.println("---华丽的分界线---");
	p.takeSubWay(10);
	System.out.println("---华丽的分界线---");
	p.atHome();
}

返回结果同上

猜你喜欢

转载自blog.csdn.net/qq_36154832/article/details/88536371