代理就像是:买家(客户端)——销售(代理对象)——工厂(目标)
买家不用直接去工厂买,而是直接通过销售就可以购买到,假设工厂生产的是杯子,那么工厂只需要提供杯子,而销售在不改变杯子的生产过程的情况下对杯子进行包装设计,广告宣传。提高其销量。
代理模式中,代理对象充当了被代理对象的中间人,客户端通过代理对象来访问被代理对象,而不是直接访问被代理对象。主要目的是在不改变原始对象的情况下,提供额外的功能或控制访问。增强了代码的安全性、灵活性。
1、动态代理是什么?
静态代理在编译时就已经确定代理类和被代理类的关系,代理类是手动编写的。在静态代理中,需要为每个被代理的类编写一个代理类。它需要手动编写代理类,当被代理的类较多时,会导致代码冗余。所以在这种情况下我们需要使用动态代理。
动态代理在运行时动态生成代理类和代理对象,不需要手动编写代理类。在动态代理中,代理类是在运行时通过反射机制动态生成的。动态代理的优点是可以减少代码冗余,缺点是相对于静态代理,它的实现稍微复杂一些。
2、JDK动态代理的实现方式
下面代码实例是通过调用经纪人代理对象调用明星的跳舞、rap方法。明星只负责工作,而在经纪人方法当中添加收钱的功能。
定义接口:我首先定义了一个Star接口,该接口有dance和rap两个接口:
public interface Star {
/**
* 跳舞
*/
public void dance();
/**
* 说唱
*/
public void rap();
}
创建Star接口实现类:在这个类当中将两个方法实现:
public class OnePeople implements Star{
@Override
public void dance() {
System.out.println("我跳舞了");
}
@Override
public void rap() {
System.out.println("我唱了rap");
}
}
创建InvocationHandler实现类:
//当调用代理对象的方法时,实际上是调用了invoke()方法。在invoke()方法中,可以根据需要执行一些前置或后置操作,然后将方法调用转发给实际的对象。
public class MyInvocationHandler implements InvocationHandler {
//被代理对象
Object object;
public MyInvocationHandler (Object o){
object = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我已经收好钱了,我的boss可以开始工作了");
//通过反射调用被代理对象的方法。
Object invoke = method.invoke(object, args);
System.out.println("我们已经工作完毕,拍拍屁股离开");
return invoke;
}
}
创建代理对象:
public class Demo {
public static void main(String[] args) {
OnePeople onePeople = new OnePeople();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(onePeople);
//newProxyInstance()接受三个参数:类加载器、要实现的接口列表和一个InvocationHandler对象
// 返回的是实现指定接口的代理类的实例。这个实例可以被强制转换为接口类型,以便在代码中使用。
Star star = (Star) Proxy.newProxyInstance(onePeople.getClass().getClassLoader(),
onePeople.getClass().getInterfaces(), myInvocationHandler);
//调用跳舞方法
star.dance();
//调用rap方法
star.rap();
}
}
运行结果:
注意:JDK动态代理只能代理接口,不能代理具体的类。如果要代理具体的类,可以考虑使用其他的代理机制(CGLIB机制)。
3、动态代理的优点
-
灵活性:动态代理可以在运行时创建代理对象,而不需要在编译时就确定代理对象的类型。这使得动态代理更加灵活,可以根据需要动态地创建不同类型的代理对象。
-
可扩展性:动态代理可以通过实现InvocationHandler接口来自定义代理对象的行为。通过在InvocationHandler中编写自定义的逻辑,可以在代理对象的方法调用前后进行额外的操作,如日志记录、性能监控、事务管理等。这种可扩展性使得动态代理在很多场景下非常有用。
-
低耦合性:动态代理可以将代理对象的创建和代理逻辑的实现分离开来,从而实现低耦合性。代理对象的创建可以由代理工厂或者依赖注入容器等负责,而代理逻辑的实现可以由InvocationHandler来完成。这种低耦合性使得代码更加清晰、易于维护和扩展。
-
动态性:动态代理可以在运行时动态地修改代理对象的行为。这意味着可以根据需要动态地添加、修改或删除代理对象的方法,从而实现更加灵活的代理逻辑。