Java代理模式——静态代理&动态代理

1. 什么是代理

1.1 例子解释

1. 生活中的例子,常见的商家卖东西,
商家就是代理,工厂是目标,买东西的人是客户端。
买东西不能找厂家买东西,工厂不卖,得找商家,
商家在其中形成了代理。
2. 房东--租房中介--租房人也是上面的关系
3. 程序中代理表示:
	 a类访问c类中的方法 但是c类不让a类访问 
	创建一个b代理 c让b访问

1.2 作用

1.功能增强 在原有的功能上 新增了额外的功能 , 新增的功能, 叫功能增强
2.控制访问 代理类不让你访问目标 如商家不让用户访问厂家
3.在项目中使用,使用别人的代码,在不改变原来目标方法功能的前提下, 
可以在代理中增强自己的功能代码

2. 静态代理

2.1 优缺点分析

	代理类是自己手工实现的,自己创建一个Java类,表示代理类。
		你所代理的目标是确定的,好理解	
	缺点: 
		目标类增多 代理类可能成倍增加 数量太多...
		接口中 增加功能后 会影响代理类多实现功能...

2.2 以厂家卖u盘用代码说明

  • 实现的功能
package com.lovely.static_proxy;

// 功能 卖u盘
public interface UsbSell {
	
	// 卖usb
	float sell(int amount);

}

  • 目标类 (a类)
package com.lovely.static_proxy;

/**
 * 目标类  
 * @author echo lovely
 *
 */
public class Factory implements UsbSell {

	// 每个u盘卖10元
	@Override
	public float sell(int amount) {

		System.out.println("工厂卖u盘");
		return 10.0f;
	}

}

  • 淘宝代理类(代理b1)
package com.lovely.static_proxy;

/**
 * 淘宝代理类 代理工厂 
 * @author echo lovely
 *
 */
public class TaoBao implements UsbSell {

	private Factory factory = new Factory();
	
	// 代理工厂
	@Override
	public float sell(int amount) {

		// 多卖了 15.0f 功能增强1
		float price = factory.sell(amount) + 15.0f;
		// 功能增强2
		System.out.println("淘宝返回优惠券");
		
		return price;
	}

}

  • 微商代理 (代理b2)
package com.lovely.static_proxy;

public class WeiSolder implements UsbSell {

	private Factory f = new Factory();
	
	@Override
	public float sell(int amount) {
		
		return f.sell(amount) + 1.0f;
	}

}

  • 客户端(a类)
package com.lovely.static_proxy;

public class BuyMain {
	
	/**
	 * 缺点 会创建许多代理对象
	 * 如果 目标很多 代理对象很多
	 * 目标增加 代理改变...
	 * @param args
	 */
	public static void main(String[] args) {
		// 通过代理类 实现买you盘 增加了 买you盘 和 优惠券...
		TaoBao tb = new TaoBao();
		float price = tb.sell(10);
		System.out.println("经过代理taobao 价格 " + price);
		
		WeiSolder w = new WeiSolder();
		price = w.sell(10);
		System.out.println("经过代理微商 价格 " + price);
	}

}

3. 动态代理

3.1 什么是动态代理

	概念
		在程序执行过程中,使用jdk的反射机制,
		创建代理类对象(无需写代理类了),
		并动态的指定要代理目标类(厂家)。
		又 : 动态代理是一种创建Java对象的能力,
		让你不用创建代理类,就能创建代理类对象。
		
		代理目标是活动的,可设置的
		给不同的目标随时创建代理
	优点:
		解决静态代理的弊端
	    在静态代理中目标类很多的时候 可使用动态代理 
		修改接口中的方法 不会影响代理类		

3.2 jdk实现原理

要求:
	jdk的动态代理 目标类与代理类必须实现相同的接口,才可代理

jdk动态代理实现:
	InvocationHandler: 只有一个invoke()方法,里面写代理类实现的功能 1. 调用目标类方法 2. 实现功能增强

	public Object invoke(Object proxy, Method method, Object[] args)
	
	InvocationHandler 接口:表示你的代理要干什么。
	使用: 
		1. 创建类实现接口 InvocationHandler
	    2. 重写invoke方法,把原来静态代理中代理类要完成的功能写在invoke中
	
	Method 类 method.invoke(目标对象,"参数值")

	Proxy 类 使用proxy类的方法 表示创建对象 代替new
	Proxy.newProxyInstance(more args...); 创建代理对象

	public static Object newProxyInstace(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
	代理目标类, 创建代理类对象(返回值)

	参数
	1. ClassLoader loader 类加载器,负责向内存中加载对象。目标对象的类加载器。
		a.getClass().getClassLoader()
	2. Class<?>[] interfaces 目标对象实现的接口
	3. InvocationHandler 代理类要完成的功能

3.3 代码描述

  • 功能接口
package com.lovely.dynamite_proxy;

// 实现卖u盘功能
public interface UsbSell {
	
	public abstract float sell(int amount);

}

  • 目标类
package com.lovely.dynamite_proxy;

public class UsbKingFactory implements UsbSell {

	@Override
	public float sell(int amount) {
		System.out.println("工厂实现卖u盘,每个" + 10.0f);
		return 10.0f;
	}

}
  • 代理类要干什么(实现目标||功能增强)
package com.lovely.dynamite_proxy;

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

/**
 * 代理类所实现的功能
 * @author echo lovely
 *
 */
public class MyInvocationHandler implements InvocationHandler {

	// 目标对象
	private Object target = null;
	
	public MyInvocationHandler(Object target) {
		this.target = target;
	}
	
	// 此方法 实现目标(卖u盘) 和 实现功能增强
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		// 调用目标对象target的 方法 
		Object returnValue = method.invoke(target, args);
		
		if (target !=  null) {
			float price = (float) returnValue;
			// 多卖20元
			price += 20.0f;
			returnValue = price;
		}
		
		System.out.println("这里调用目标方法,还可做其它操作,如写一些其它功能");
		
		return returnValue;
	}

}

  • 创建代理对象,实现动态代理需求
package com.lovely.dynamite_proxy;

import java.lang.reflect.Proxy;

public class BuyMain {
	
	public static void main(String[] args) {
		// 创建目标对象
		UsbSell usbKing = new UsbKingFactory();
		
		// 创建实现目标 功能类
		MyInvocationHandler handler = new MyInvocationHandler(usbKing);
			
		// System.out.println(UsbKingFactory.class.getInterfaces()[0].getName());
		// System.out.println(UsbKingFactory.class.getClassLoader());
		
		// 创建代理对象
		UsbSell proxy = (UsbSell)Proxy.newProxyInstance(UsbKingFactory.class.getClassLoader(), 
				UsbKingFactory.class.getInterfaces(), handler);
		float price = proxy.sell(1);
	
		System.out.println("价格为 " + price);
	}

}

工厂实现卖u盘,每个10.0
这里调用目标方法,还可做其它操作,如写一些其它功能
价格为 30.0
  • 关于动态代理另一种实现cglib
cglib(code generating libray)动态代理: 第三方的工具库 创建代理对象
	原理是继承: cglib通过继承目标类 创建子类 重写方法 对功能修改

	对于无接口的类 使用cglib实现

	cglib在spring mybatis中使用较多

猜你喜欢

转载自blog.csdn.net/qq_44783283/article/details/107591174