【04】Java–代理模式
代理模式有两种:
- 动态代理
- 静态代理
通俗的说:Java里面的代理其实和生活中的代理商,代购的意思类似。假设有一个场景,里面有生产厂家,消费者,代理商。我们一般都是通过代理商进行购买的,然后代理商向厂家拿货。这就是代理
那么动态代理和静态代理有什么区别呢?
- 动态代理没有固定的代理商,都是临时找的。
- 静态代理的话是有一个固定的代理商。
Java里:
- 动态代理:没有固定的类,什么时候用,什么时候创建(灵活性好
- 静态代理:有一个固定的类,在使用代理的时候,直接通过静态工厂获取即可使用
一、静态代理:
要求:
- 代理类和被代理类需要实现相同的接口
- 通过静态工厂向外提供代理对象
1 生产厂家接口:
package indi.indi.xu.proxy3;
/**
* @author a_apple
* @create 2020-01-15 15:56
*/
public interface IProducer {
/**
* 销售方法
* @param money
*/
void sale(Integer money);
/**
* 维修方法
* @param money
*/
void fix(Integer money);
}
2 生产厂家:
package indi.indi.xu.proxy3;
/**生产厂家:
* 无代理:直接向厂家购买的话,你付多少钱,厂家就会收到多少
*
* 代理:你给代理钱,代理给厂家钱,赚取差价。此时厂家收到的并不是你付的所有钱
* @author a_apple
* @create 2020-01-15 15:56
*/
public class Producer implements IProducer{
public void sale(Integer money) {
System.out.println("出售一件商品,厂家获得:"+money);
}
public void fix(Integer money) {
System.out.println("维修商品,厂家获得:"+money);
}
}
3 静态代理:
里面内置了一个实现了接口的生产厂家类,并对它的方法进行增强
package indi.indi.xu.proxy3;
/**
* 静态代理:
*
* @author a_apple
* @create 2020-01-15 16:26
*/
public class StaticProxyProducer implements IProducer {
private Producer producer;
public StaticProxyProducer(Producer producer) {
this.producer = producer;
}
public void sale(Integer money) {
producer.sale((int) (money * 0.6));
}
public void fix(Integer money) {
producer.fix((int) (money * 0.8));
}
}
4 静态代理工厂:
package indi.indi.xu.proxy3;
/**静态工厂:
* 客户通过静态工厂获取代理对象
* @author a_apple
* @create 2020-01-15 16:31
*/
public class StaticFactory {
public static IProducer getProxyProducer(){
return new StaticProxyProducer(new Producer());
}
}
5 消费者:
package indi.indi.xu.proxy3;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**消费者
*
* 如果原厂价为6000元:
* 直接向厂家购买:付6000
* 通过代理购买:付10000
* @author a_apple
* @create 2020-01-15 16:03
*/
public class Client {
public static final Producer producer = new Producer();
public static void main(String[] args) {
//直接从厂家购买
fromProducer(6000);
//静态代理
fromStaticProxy(10000);
}
/**
* 直接从厂家购买
* @param money
*/
public static void fromProducer(Integer money){
System.out.println("直接向厂家购买:");
System.out.println("付款:"+money);
producer.sale(money);
}
/**
* 静态代理:
*/
public static void fromStaticProxy(int money){
System.out.println("\n通过静态代理购买:");
System.out.println("付款:"+money);
IProducer proxyProducer = StaticFactory.getProxyProducer();
proxyProducer.sale(money);
}
}
二、动态代理:
分类、要求:
- 基于接口的动态代理:被代理类(Producer)最少实现一个接口(IProducer),如果没有则不能使用
- 基于子类的动态代理:被代理类(Producer)不能用 final 修饰。(无法创建子类了
1 生产厂家和接口和上面一样
1-动态代理:基于接口
/**动态代理:基于接口
*
* 通过代理购买
* @param money
*/
public static void fromProducerProxy(Integer money){
System.out.println("\n(基于接口)通过动态代理购买:");
System.out.println("付款:"+money);
IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(
producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnValue = null;
//1.获取方法名,判断是否是销售方法
if ("sale".equals(method.getName())) {
//2.获取方法参数
Integer money = (Integer) args[0];
//3.增强、执行方法
returnValue = method.invoke(producer, (int) (money * 0.6));
}
//4.返回方法返回值
return returnValue;
}
});
proxyProducer.sale(10000);
}
2-动态代理:基于子类
/**
* 动态代理:基于子类
*
* @param money
*/
public static void fromSubProducerProxy(Integer money){
System.out.println("\n(基于子类)通过动态代理购买:");
System.out.println("付款:"+money);
//代理对象
Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 作用:执行被代理对象的任何接口方法都会经过该方法
* @param proxy 代理对象的引用(proxyProducer
* @param method 当前执行的方法
* @param args 当前执行方法所需的参数
*
* @param methodProxy 当前执行方法的代理对象(一般不用
* @return
* @throws Throwable 和被代理对象方法具有相同的返回值.(返回的是Objec,需要再强转一下
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//提供增强的方法
Object returnValue = null;
//2.获取当前方法名,判断是不是销售方法
if("sale".equals(method.getName())){
//1.获取方法执行的参数
Integer money = (Integer)args[0];
returnValue = method.invoke(producer, (int) (money * 0.6));
}
return returnValue;
}
});
cglibProducer.sale(10000);
}
Client:
public class Client {
public static final Producer producer = new Producer();
public static void main(String[] args) {
//直接从厂家购买
fromProducer(6000);
//动态代理-基于接口
fromProducerProxy(10000);
//动态代理-基于子类
fromSubProducerProxy(10000);
//静态代理
fromStaticProxy(10000);
}
....
}
结果:
直接向厂家购买:
付款:6000
出售一件商品,厂家获得:6000
(基于接口)通过动态代理购买:
付款:10000
出售一件商品,厂家获得:6000
(基于子类)通过动态代理购买:
付款:10000
出售一件商品,厂家获得:6000
通过静态代理购买:
付款:10000
出售一件商品,厂家获得:6000
三、两种代理的比较:
- 当一个实现不同接口的对象需要代理时,静态代理实现时需要对每个接口编写一个代理类。所以当接口比较多的时候,静态代理就不合适了
- 动态代理可以通过对生成代理类方法的调用,传入需要实现的接口,动态生成实现不同接口的代理类,操作方便。