1、代理就是帮别人做事情
如:工厂的中介,中介负责为工厂招收工人,那么中介就是工厂的代理;客户通过商家购买东西,商家向厂家购买货物,商家就是工厂的代理
2、在开发中存在 a类需要调用c类的方法,完成某一个功能,但是c禁止a调用。
这时,可以在a和c之间创建一个b类代理,a类访问b类,b类访问c类。例如:登录的时候需要进行短信验证,这个时候代理就是中国移动的子公司来完成短信的发送功能
3、代理模式 就是为其他对象提供一种代理来控制这个对象的访问,在某些情况下一个对象不适合或不能直接引用另一个对象,而代理对象可以在客户类和目标对象直接起到中介的作用
代理模式能带给我们控制访问某个对象的能力,在某些情况下,一个对象的某些方法想要进行屏蔽或者某种逻辑的控制,则我们可以通过代理的方式进行。再此能力上,引申出来的作用,也是目前在开发中经常使用的一个作用,就是——“在不修改原对象代码的基础上,对原对象的功能进行修改或者增强”。
有两种模式:静态代理、动态代理
例如:A类(用户)-> B类中介 -> C类(目标)
具体实现的代码逻辑:
实现步骤:
用户访问商家类,而用户不能直接访问厂家类
// 表示功能的,厂家,商家都要完成的功能
public interface UsbSell {
//定义方法 参数 amount:表示一次购买的数量,暂时不用
//返回值表示一个u盘的价格。
float sell(int amount);
//可以多个其它的方法
//void print();
}
//目标类: 金士顿厂家, 不接受用户的单独购买。
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
System.out.println("目标类中的方法调用 , UsbKingFactory 中的sell ");
//一个128G的u盘是 85元。
//后期根据amount ,可以实现不同的价格,例如10000个,单击是80, 50000个75
return 85.0f;
}
}
先访问C类,才能给A类
//taobao是一个商家,代理金士顿u盘的销售。
public class TaoBao implements UsbSell {
//声明 商家代理的厂家具体是谁
private UsbKingFactory factory = new UsbKingFactory();
@Override
//实现销售u盘功能
public float sell(int amount) {
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell(amount); //厂家的价格。
//商家 需要加价, 也就是代理要增加价格。
price = price + 25; //增强功能,代理类在完成目标类方法调用后,增强了功能。
//在目标类的方法调用后,你做的其它功能,都是增强的意思。
System.out.println("淘宝商家,给你返一个优惠券,或者红包");
//增加的价格
return price;
}
}
public class shopMain {
public static void main(String[] args){
// 创建代理的商家淘宝对象
TaoBao taoBao = new TaoBao();
// 我只向淘宝买一件产品,得到报价
float price = taoBao.sell(2);
System.out.println("购买一件产品.淘宝的报价为: "+price);
}
}
输出:
目标类中的方法调用 , UsbKingFactory 中的sell
淘宝商家,给你返一个优惠券,或者红包
110.0
优点:
缺点:
例如:上例中创建了一个工厂类,那么该类只能代表一个工厂,当建立了其它品牌的工厂后,还需要为该工厂创建代理类
比如:目标C类,代理B类都需要修改。不修改可不行,因为接口的实现类必须都要实现。
为了解决静态的缺点,产生了动态代理
当静态代理的目标类C很多的时候,可以使用动态代理
动态代理的实现方式有两种:一种是JDK动态代理,一种是CGLIB动态代理
-> 反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy
-> 在子类中重写父类同名方法,实现功能修改(重写的方法不能是final)
在 Java 动态代理机制中 InvocationHandler 接口和 Proxy 类是核心。
Proxy 类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
}
这个方法一共有 3 个参数:
要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。
当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。
public interface InvocationHandler {
/**
* 当你使用代理对象调用方法的时候实际会调用到这个方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
invoke() 方法有下面三个参数:
也就是说:
你通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。
你可以在 invoke() 方法中自定义处理逻辑,比如在方法执行前后做什么事情。
代理类完成的功能
1.调用目标方法,执行目标方法的功能
2.功能增强,在目标方法调用时,增加功能
Method类:表示方法的,确切的说就是目标类中的方法。
作用:
通过 Method可以执行某个目标类的方法, Method. invoke();
method. invoke(目标对象,方法的参数)
object ret= method. invoke(service22,"李四")
说明:
method.invoke()就是为了用来执行目标方法的,等同于静态代理中的
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
float price = factory.sell(amount);
proxy类:
核心的对象,创建代理对象。之前创建对象都是new(),现在是使用proxy类的方法,代替new的使用。
方法:静态方法 newProxyInstance()
作用是:创建代理对象,等同于静态代理中的TaoBao taoBao=new TaoBao()
我们来观察方法原型
/**
*
* @param loader 被代理类的类加载器,不用多说,没这个怎么反射去找被代理类的信息
* @param interfaces 被代理类实现的接口
* @param h InvocationHandler的实现类
* @return
* @throws IllegalArgumentException
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数:
返回值:
代理对象
public interface service {
public void reduceStock();
}
public class ServiceImpl implements service {
//业务方法
@Override
public void reduceStock() {
System.out.println("扣减库存开始");
}
}
需要实现InvocationHandler接口,重写invoke方法,这里可以对方法进行增强。
public class Dynamicproxy implements InvocationHandler {
private Object targetObject;
public Dynamicproxy(Object targetObject) {
this.targetObject = targetObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("日志开始");
Object invoke = method.invoke(targetObject, args);
System.out.println("日志结束");
return invoke;
}
}
public class TestApp {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 创建代理对象
// 1. 创建目标对象 --》 实现接口的业务类
Service service = new ServiceImpl();
// 2. 创建代理类对象 --》 InvocationHandler对象
InvocationHandler handler = new Dynamicproxy(service);
// 3. 创建代理对象
Service o = (Service) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(),
service.getClass().getInterfaces(), handler);
// 4. 通过代理执行方法
// o.reduceStock();
// 使用匿名内部类的写法:
Service o1 = (Service) Proxy.newProxyInstance(
service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("哈哈哈哈");
Object invoke = method.invoke(service, args);
System.out.println("嘿嘿嘿");
return invoke;
}
});
o1.reduceStock();
}
}
o.reduceStock();
输出:
Proxy类,实现动态代理的流程,使用返回指定接口的代理类实例
我们此时debug一下程序,在invok实现类中打一个断点
此时我们再观察,代理对象MyHandler里面的invoke方法的参数
使用步骤
案例编写:
不同于 JDK 动态代理不需要额外的依赖。 CGLIBopen in new window(Code Generation Library) 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖。
cglib
cglib
3.3.0
public class AliSmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 自定义MethodInterceptor
*/
public class DebugMethodInterceptor implements MethodInterceptor {
/**
* @param o 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param args 方法入参
* @param methodProxy 用于调用原始方法
*/
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//调用方法之前,我们可以添加自己的操作
System.out.println("before method " + method.getName());
Object object = methodProxy.invokeSuper(o, args);
//调用方法之后,我们同样可以添加自己的操作
System.out.println("after method " + method.getName());
return object;
}
}
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new DebugMethodInterceptor());
// 创建代理类
return enhancer.create();
}
}
AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
aliSmsService.send("java");
运行上述代码之后,控制台打印出:
before method send
send message:java
after method send
页面更新:2024-03-08
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号