1.什么是动态代理 ?
- 使用jdk的反射机制,创建对象的能力, 创建的是代理类的对象。
- 动态:在程序执行时,调用jdk提供的方法才能创建代理类的对象。
- jdk动态代理,必须有接口,目标类必须实现接口, 没有接口时,需要使用cglib动态代理
2.知道动态代理能做什么 ?
- 可以在不改变原来目标方法功能的前提下, 可以在代理中增强自己的功能代码。程序开发中的意思,比如:你所在的项目中,有一个功能是其他人(公司的其它部门,其它小组的人)写好的,你可以使用。
你发现这个功能,现在还缺点, 不能完全满足我项目的需要。 我需要在gn.print()执行后,需要自己在增加代码。用代理实现 gn.print()调用时, 增加自己代码, 而不用去改原来的 GoNong文件。GoNong.class , GoNong gn = new GoNong(), gn.print();
代理模式
1. 代理
代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。
换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。
客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。当然,代理类与目标类要实现同一个接口。
例如: 有 A,B,C 三个类, A 原来可以调用 C 类的方法, 现在因为某种原因 C 类不允许 A 类调用其方法,但 B 类可以调用 C 类的方法。A 类通过 B 类调用 C 类的方法。这里 B 是 C 的代理。 A 通过代理 B 访问 C.
原来的访问关系:
通过代理的访问关系:
Window 系统的快捷方式也是一种代理模式。快捷方式代理的是真实的程序,双击快捷方式是启动它代表的程序。
代购, 中介,换ip,商家等等:比如有一家美国的大学, 可以对全世界招生。 留学中介(代理)
留学中介(代理): 帮助这家美国的学校招生, 中介是学校的代理, 中介是代替学校完成招生功能。
代理特点:
- 中介和代理他们要做的事情是一致的: 招生。
- 中介是学校代理, 学校是目标。
- 家长—中介(学校介绍,办入学手续)----美国学校。
- 中介是代理,不能白干活,需要收取费用。
- 代理不让你访问到目标。
为什么要找中介 ?
- 中介是专业的, 方便
- 家长现在不能自己去找学校。 家长没有能力访问学校。 或者美国学校不接收个人来访。
买东西都是商家卖, 商家是某个商品的代理, 你个人买东西, 肯定不会让你接触到厂家的。
1.1 在开发中也会有这样的情况, 你有 a 类, 本来是调用 c 类的方法, 完成某个功能。 但是 c 不让 a 调用。
a 不能调用 c 的方法。
在 a 和 c 直接创建一个 b 代理,c 让 b 访问。
a 访问 b 访问c
实际的例子: 登录,注册有验证码, 验证码是手机短信。
中国移动, 联通能发短信。
中国移动, 联通能有子公司,或者关联公司,他们面向社会提供短信的发送功能
张三项目发送短信----子公司,或者关联公司-----中国移动, 联通
1.2 使用代理模式的作用
- 功能增强: 在你原有的功能上,增加了额外的功能。 新增加的功能,叫做功能增强。
- 控制访问: 代理类不让你访问目标,例如商家不让用户访问厂家。
1.3 代理模式分类
可以将代理分为两类:静态代理与动态代理
1.4 实现代理的方式
1.4.1 需求
需求:用户需要购买 u 盘,u 盘厂家不单独接待零散购买,厂家规定一次最少购买 1000 个以上,用户可以通过淘宝的代理商,或者微商哪里进行购买。
淘宝上的商品,微商都是 u 盘工厂的代理商, 他们代理对 u 盘的销售业务。
用户购买-------代理商(淘宝,微商)----- u 厂家(金士顿,闪迪等不同的厂家)
模拟一个用户购买u盘的行为。
用户是客户端类
商家:代理,代理某个品牌的u盘。
厂家:目标类。
三者的关系: 用户(客户端)---商家(代理)---厂家(目标)
商家和厂家都是卖u盘的,他们完成的功能是一致的,都是卖u盘。
设计这个业务需要的类,实现步骤:
1. 创建一个接口,定义卖u盘的方法, 表示你的厂家和商家做的事情。(商家和厂家都是提供 sell 购买 u 盘的方法。)
2. 创建厂家类,实现1步骤的接口
3. 创建商家,就是代理,也需要实现1步骤中的接口。
4. 创建客户端类,调用商家的方法买一个u盘。
代理类完成的功能:
1. 目标类中方法的调用
2. 功能增强
1.4.2 静态代理 :
在 idea 中创建 java 工程:Dynamic
定义业务接口 usbSell(目标接口),其中含有抽象方法 sell(int amount), sell 是目标方法
1.创建一个接口,定义卖u盘的方法,业务接口 usbSell(目标接口), 其中含有抽象方法 sell(int amount), sell 是目标方法,表示你的厂家和商家做的事情
package com.lqh.service;
public interface usbSell {
/**
* 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
* 返回值表示一个u盘的价格
* @param amount
* @return
*/
float sell(int amount);
}
2.创建厂家类,实现1步骤的接口
package com.lqh.factory;
import com.lqh.service.usbSell;
//目标类:金士顿厂家,不接受用户的单独购买
public class UsbKingFactory implements usbSell {
/**
* 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
* 返回值表示一个u盘的价格
*
* @param amount
* @return
*/
@Override
//一个 128G 的 U 盘是 85 元.
// 后期根据 amount,可以实现不同的价格,例如10000个,单击是80,50000个75
public float sell(int amount) {
return 85.0f*amount;
}
}
3.创建商家,就是代理,也需要实现1步骤中的接口
package com.lqh.business;
import com.lqh.factory.UsbKingFactory;
import com.lqh.service.usbSell;
//淘宝是一个商家,代理金士顿U盘的销售
public class TaoBao implements usbSell {
// 声明 商家代理的厂家具体是谁
private UsbKingFactory factory =new UsbKingFactory();
@Override
//实现销售U盘功能
public float sell(int amount) {
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
float price = factory.sell(amount);
// 商家需要加价也就是代理要增加价格,在单价之上,增加 25 元作为利润
price = price + 25;
// 在目标类的方法调用后,你做的其他功能,都是增强的意思
System.out.println("淘宝再给你返回一个优惠券, 或者红包");
// 增加的价格
return price;
}
}
4.创建客户端类,调用商家的方法买一个u盘
package com.lqh;
import com.lqh.business.TaoBao;
public class shopMain {
public static void main(String[] args){
// 创建代理的商家淘宝对象
TaoBao taoBao = new TaoBao();
// 我只向淘宝买一件产品,得到报价
float price = taoBao.sell(1);
System.out.println("购买一件产品.淘宝的报价为: "+price);
}
}
使用代理的访问关系图:
- 1)代理类是自己手工实现的,自己创建一个java类,表示代理类。
- 2)同时你所要代理的目标类是确定的。
特点: 1)实现简单 2)容易理解。
缺点: 当你的项目中,目标类和代理类很多时候,有以下的缺点:
- 1) 代码复杂,难于管理:当目标类增加了, 代理类可能也需要成倍的增加。 代理类数量过多。
- 2) 代理类依赖目标类,代理类过多:当你的接口中功能增加了, 或者修改了,会影响众多的实现类,厂家类,代理都需要修改。影响比较多。
1.4.3 动态代理
在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
动态代理中目标类即使很多, 1)代理类数量可以很少, 2)当你修改了接口中的方法时,不会影响代理类。
动态代理: 在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。动态代理不需要定义代理类的.java 源文件。(动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。)
换句话说: 动态代理是一种创建java对象的能力,让你不用创建TaoBao类,就能创建代理类对象。
在 java 中,要想创建对象:
- 创建类文件, java文件编译为class
- 使用构造方法,创建类的对象。
动态代理的实现方式常用的有两种:使用 JDK 代理,与通过 CGLIB 动态代理。
动态代理的实现:
-
jdk 动态代理(理解): 使用 java 反射包中的类和接口实现动态代理的功能。反射包 java.lang.reflect , 里面有三个类 : InvocationHandler, Method, Proxy. (Jdk 的动态要求目标对象必须实现接口,这是 java 设计上的要求。)
-
cglib动态代理(了解): cglib是第三方的工具库, 创建代理对象。 cglib的原理是继承, cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法, 实现功能的修改。因为cglib是继承,重写方法,所以要求目标类不能是final的, 方法也不能是final的。cglib的要求目标类比较宽松, 只要能继承就可以了。cglib在很多的框架中使用, 比如 mybatis ,spring框架中都有使用。
jdk 动态代理:
- 反射, Method 类,表示方法。类中的方法。 通过 Method 可以执行某个方法。
回顾反射 Method类
Method类的结构图
- Class Method
- java.lang.Object
- java.lang.reflect.AccessibleObject
- java.lang.reflect.Executable
- java.lang.reflect.Method
- java.lang.reflect.Executable
- java.lang.reflect.AccessibleObject
- java.lang.Object
创建接口 HelloService
package com.lqh.service;
public interface HelloService {
public void sayHello(String name);
}
创建 HelloServiceIml 类
package com.lqh.service;
public class HelloServiceIml implements HelloService {
@Override
public void sayHello(String name) {
System.out.println("你好" + name);
}
}
创建 TestApp 类
package com.lqh;
import com.lqh.service.HelloServiceIml;
import com.lqh.service.HelloService;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestApp {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// HelloService service = new HelloServiceImpl();
// service.sayhello("张三");
// 以上是常规方法执行sayhello
// 下面我们使用反射机制进行创建sayhello方法,核心Method(类中的方法)
HelloServiceIml target = new HelloServiceIml();
// 获取sayhello名称对应的Method类对象
// public Method getM ethod(String name, Class<?>... parameterTypes)
// 加入,该方法的参数有多个该怎么办?
// parameterTypes参数是一个类对象数组,按声明的顺序标识方法的形式参数类型。
Method method = HelloService.class.getMethod("sayHello", String.class);
// 通过Metho可以执行sayhello方法的调用
/*
* public Object invoke(Object obj, Object... args)
* 表示执行方法的调用
* 参数:
* 1.Object,表示对象,要执行这个对象的方法
* 2.Object...args,方法执行时的参数值
* 返回值:
* Object:方法执行后的返回值
* */
Object ret = method.invoke(target, "李四");
}
}
- // 通过反射创建 HelloServiceIml 的实例:Class<?> clazz = Class.forName(“com.lqh.service.HelloServiceIml”);
- HelloServiceIml target = (HelloServiceIml) clazz.getDeclaredConstructor().newInstance();
- jdk 动态代理的实现反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy.
1) InvocationHandler 接口(调用处理器):就一个方法 invoke()
InvocationHandler 接口叫做调用处理器,负责完调用目标方法,并增强功能。
通过代理对象执行目标接口中的方法,会把方法的调用分派给调用处理(InvocationHandler)的实现类,执行实现类中的 invoke() 方法,我们需要把功能代理写在 invoke() 方法中 。
invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在 invoke() 方法中。
代理类完成的功能:
1. 调用目标方法,执行目标方法的功能
2. 功能增强,在目标方法调用时,增加功能。
方法原型:public Object invoke(Object proxy, Method method, Object[] args)
参数: Object proxy:jdk创建的代理对象,无需赋值。
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数, jdk提供的。
InvocationHandler 接口:表示你的代理要干什么。
怎么用: 1.创建类实现接口InvocationHandler
2.重写invoke()方法, 把原来静态代理中代理类要完成的功能,写在这。
2)Method类:表示方法的, 确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
Object ret = method.invoke(service2, "李四");
说明: method.invoke()就是用来执行目标方法的,等同于静态代理中的
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell(amount); //厂家的价格。
3)Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法(),现在我们是使用Proxy类的方法,代替new的使用。
方法: 静态方法 newProxyInstance()
作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao();
参数:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
1. ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader类a , a.getCalss().getClassLoader(), 目标对象的类加载器
2. Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
3. InvocationHandler h : 我们自己写的,代理类要完成的功能。
返回值:就是代理对象
1.4.4 实现动态代理的步骤:
1. 创建接口,定义目标类要完成的功能
2. 创建目标类实现接口
3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
1.调用目标方法
2.增强功能
4. 使用 Proxy 类的静态方法,创建代理对象。 并把返回值转为接口类型。
第一步:创建接口, 定义目标所需功能
package com.lqh.service;
public interface usbSell {
/**
* 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
* 返回值表示一个u盘的价格
* @param amount
* @return
*/
float sell(int amount);
}
第二步:创建目标类实现接口
package com.lqh.factory;
import com.lqh.service.usbSell;
//目标类:金士顿厂家,不接受用户的单独购买
public class UsbKingFactory implements usbSell {
/**
* 定义一个方法 参数 amount:表示一次购买的数量,暂时不用
* 返回值表示一个u盘的价格
*
* @param amount
* @return
*/
@Override
//一个 128G 的 U 盘是 85 元.
// 后期根据 amount,可以实现不同的价格,例如10000个,单击是80,50000个75
public float sell(int amount) {
return 85.0f*amount;
}
}
我们写了接口类, 定义了功能, 写了代理类, 实现了接口功能, 按照以前的操作, 现在就需要写一个真正的代理类, 创建对象,比如前面的 TaoBao 类,但是现在不需要了,看如下:
第三步: 创建 Invocationhandler 实现类. 在 invoke() 方法中完成代理类的对象
- 调用目标的方法
- 增强功能
package com.lqh.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 必须要实现 InvocationHandler 接口,完成代理类要做的功能(1. 调用目标方法 2. 功能增强)
public class MyHandle implements InvocationHandler {
private Object target = null;
// 动态代理中,目标对象是活动的,不是固定的,需要传入进来
// 传入的是谁,就给谁创建代理。
public MyHandle(Object target) {
// 给目标对象赋值
this.target = target;
}
@Override // 这里执行目标类,并在此基础上增加功能
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = null;
// 向厂家发送订单,告诉厂家,我买了U盘,厂家发货
// 发送给工厂,我需要的订单,返回报价
res = method.invoke(target, args); // 执行目标对象
// 商家需要加价也就是代理要增加价格,在单价之上,增加 25 元作为利润
// price = price + 25;
if (res != null) {
Float price = (Float) res;
price = price + 25;
res = price;
}
// 在目标类的方法调用后,你做的其他功能,都是增强的意思
System.out.println("淘宝再给你返回一个优惠券, 或者红包");
// 增加的价格
return res;
}
}
第四步:使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型
创建一个MainShop类.
package com.lqh;
import com.lqh.factory.UsbKingFactory;
import com.lqh.handler.MyHandle;
import com.lqh.service.usbSell;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class MainShop {
public static void main(String[] args){
// 1.创建对象,使用Proxy
// 2.创建目标对象
usbSell factory = new UsbKingFactory();
// 3.创建Invocationhandler对象
InvocationHandler myHandle = new MyHandle(factory);
// 4.创建代理对象
usbSell proxy = (usbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
myHandle);
// 通过代理执行方法
float price = proxy.sell(1);
System.out.println("通过动态代理对象,调用方法:" + price);
}
}
只需要通过第 4 步来创建代理对象,不需要想上面创建很多的类了
// proxycom.sun.proxy.$Proxy0:jdk 动态代理创建的对象类型
System.out.println("proxy" + proxy.getClass().getName());
2. JDK动态代理执行流程
我们先复习一下 ,Proxy类, 实现动态代理的流程, 使用返回指定接口的代理类实例,
我们此时debug一下程序,在invok实现类中打一个断点
此时我们再观察,代理对象MyHandler里面的invoke方法的参数
3. 动态代理应用
我们需要知道代理能做什么?
在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码,程序开发中的意思,
比如:你所在的项目,有一个功能是其他人(公司其他部门,其他小组的人)写好的,你可以使用
//比如,同事开发一个GoNong类
GoNong.class ,
GoNong gn=new GoNong()
//我们需要增加一个print方法
我们发现这个功能现在还存在缺点,不能完全满足我项目的需要,我需要在print()执行过后,需要自己再增加代理,使用什么方法那,肯定是代理,因为别人不会让我们看源文件
执行步骤:
1.我们先建立一个接口功能,很简单的一个功能
public interface HelloService {
/**
* 打印报表,报表
* @param name
* @return
*/
int print (String name);
}
2.我们再加个接口实现类,GoNeng 别人已经写好了,我们不能改动这个写好的代码
public class GoNeng implements HelloService {
@Override
public int print(String name) {
System.out.println("其他人写好的这个方法!" + name);
return 2;
}
}
3.我们如果想对上述功能进行修改,我们不可能直接去在原方法上进行修改
问题是如果我们想修改这个功能该怎么办?在不修改源代码的基础上,我们可以创建一个代理类,来增强这个类方法,
4.设置一个代理类实现功能的增强和代理
public class MyInvocationHandler implements InvocationHandler {
private Object target=null;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用目标方法,执行print()得到2
Object res = method.invoke(target,args); //返回为2的结果
//我们可以把结果再乘以2
if (res!=null)
{
Integer num = (Integer) res;
res = num*2;
}
return null;
}
}
5.我们仍回到主方法里面进行测试
public class MyApp {
public static void main(String[] args){
// GoNeng gn = new GoNeng();
// int i = gn.print("nihao1");
// System.out.println("num" +i);
GoNeng goNeng = new GoNeng();
InvocationHandler handler = new MyInvocationHandler(goNeng);
HelloService proxy = (HelloService) Proxy.newProxyInstance(goNeng.getClass().getClassLoader(), goNeng.getClass().getInterfaces(),
handler);
int num = proxy.print("市场");
System.out.println("我们期望得到的 num =="+num);
}
}
我们期望得到的 num ==4
动态代理过程中:多个接口
在 Java 动态代理中,代理类通常会实现一个或多个接口。具体来说,代理类可以实现多个接口,只要目标对象实现了这些接口。
动态代理是通过 Proxy.newProxyInstance
方法创建的代理对象,该方法的参数之一是一个 Class[]
类型的接口数组,表示代理类将要实现的接口。因此,如果目标对象实现了多个接口,代理类就可以实现这些接口。
示例:
假设我们有两个接口 HelloService
和 AnotherService
,以及一个类 GoNeng
实现了这两个接口:
public interface HelloService {
int print(String name);
}
public interface AnotherService {
void sayHello();
}
public class GoNeng implements HelloService, AnotherService {
@Override
public int print(String name) {
System.out.println("Hello, " + name);
return 2;
}
@Override
public void sayHello() {
System.out.println("Hello from AnotherService");
}
}
然后,在创建代理类时,我们可以让代理类实现多个接口:
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用目标方法之前增强功能
System.out.println("Before method: " + method.getName());
// 调用目标方法
Object result = method.invoke(target, args);
// 在调用目标方法之后增强功能
System.out.println("After method: " + method.getName());
return result;
}
}
public class MyApp {
public static void main(String[] args) {
GoNeng goNeng = new GoNeng();
InvocationHandler handler = new MyInvocationHandler(goNeng);
// 代理多个接口
HelloService proxy = (HelloService) Proxy.newProxyInstance(
goNeng.getClass().getClassLoader(),
new Class[] { HelloService.class, AnotherService.class },
handler);
proxy.print("John");
((AnotherService) proxy).sayHello();
}
}
在上面的代码中:
GoNeng
实现了HelloService
和AnotherService
两个接口。- 使用
Proxy.newProxyInstance
创建的代理类可以同时实现这两个接口。 - 在
MyInvocationHandler
中增强了方法执行前后的逻辑。
输出结果:
Before method: print
Hello, John
After method: print
Before method: sayHello
Hello from AnotherService
After method: sayHello
总结:
- 动态代理可以实现多个接口,只要目标类实现了多个接口。
- 你可以通过
Proxy.newProxyInstance
传入一个接口数组来创建一个同时实现多个接口的代理类。 - 在使用动态代理时,目标对象可以是多个接口的实现类,代理对象会相应地实现这些接口。
动态代理:一个接口多个方法
public interface HelloService {
int print(String name); // 方法1
void sayHello(); // 方法2
}
这个接口有两个方法:print(String name)
和 sayHello()
。当你创建一个动态代理时,代理对象将实现接口中定义的所有方法。
代理实现
假设我们有一个实现了 HelloService
接口的类 GoNeng
:
public class GoNeng implements HelloService {
@Override
public int print(String name) {
System.out.println("Hello, " + name);
return 2;
}
@Override
public void sayHello() {
System.out.println("Say Hello!");
}
}
然后,我们创建一个 InvocationHandler
,用于增强 HelloService
接口中的所有方法:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增强:在调用目标方法之前做一些操作
System.out.println("Before calling method: " + method.getName());
// 调用目标方法
Object result = method.invoke(target, args);
// 增强:在调用目标方法之后做一些操作
System.out.println("After calling method: " + method.getName());
return result;
}
}
使用动态代理
import java.lang.reflect.*;
public class MyApp {
public static void main(String[] args) {
GoNeng goNeng = new GoNeng();
InvocationHandler handler = new MyInvocationHandler(goNeng);
// 创建代理对象,代理 HelloService 接口
HelloService proxy = (HelloService) Proxy.newProxyInstance(
goNeng.getClass().getClassLoader(),
new Class[] { HelloService.class }, // 代理多个方法的接口
handler);
// 调用代理对象的方法
int result = proxy.print("John");
System.out.println("Result from print: " + result);
proxy.sayHello();
}
}
输出结果:
Before calling method: print
Hello, John
After calling method: print
Result from print: 2
Before calling method: sayHello
Say Hello!
After calling method: sayHello
解释:
- 在
MyInvocationHandler
中,invoke
方法会为HelloService
接口中的所有方法提供增强行为。在每个方法调用前后,我们都打印了日志信息。 - 无论
HelloService
接口有多少个方法,代理都会对这些方法提供统一的增强。这里,print
和sayHello
都被增强了。 Proxy.newProxyInstance
创建的代理对象会实现HelloService
接口,并为接口中的每个方法都提供代理。
总结:
- 一个接口多个方法:接口可以包含多个方法,这样的设计在实际开发中非常常见。
- 动态代理支持多个方法:当你使用 Java 动态代理时,代理对象会实现接口中的所有方法,无论接口有多少个方法。
- 增强行为:通过
InvocationHandler
,你可以为接口中的所有方法提供统一的增强行为(如日志、缓存、权限检查等)。