目录
-
原理
-
基于反射机制
-
a想要访问c,但是a没有访问c的权限;这是可在a、c之间创建一个可以被a访问且能访问c的b;a就可以通过访问b,让b去访问c,间接访问c;并且还可以在b上实现更多的业务
-
-
暂时的掌握程度
-
先做了解,之后学mybatis和spring再学习怎么用
-
知道是什么动态代理?
-
知道动态代理能做什么?
-
-
动态代理模式的作用
-
功能增强:在原有基础上增加新功能;除了接口的实现功能外,其他功能都是增强功能
-
控制访问:代理类可不让你访问目标
-
-
静态代理
-
需要手动实现,创建一个Java类来作为代理类
-
优缺点:
-
优点:实现简单、容易理解
-
缺点:代理类过多、难修改(需要一个个修改)
-
-
例子
-
需求:模拟一个用户购买某品牌U盘
-
用户是客户端类;商家是代理类,代理某品牌的U盘;厂家是目标类
-
商家和厂家都是卖U盘的,他们完成的功能是一致的,都是卖U盘
-
-
实现步骤:
-
创建一个接口,定义卖U盘的方法,表示你的厂家和商家做的事情
-
创建厂家类,实现步骤1的接口
-
创建商家类(代理类),同样要实现步骤1的接口
-
创建客户端类,调用商家的方法买U盘
-
-
-
-
动态代理
-
什么是动态代理:
-
使用jdk的反射机制,创建对象的能力,创建的是代理类的对象。不需要我们创建类文件
-
动态:在程序执行时,调用jdk提供的方法才能创建代理类的对象
-
-
优点:
-
避免了静态代理的缺点,代理类数量可以很少,修改接口中的方法时不会影响代理类
-
-
实现:
-
在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理的目标类
-
简而言之:不用创建代理类就能够创建代理对象(接口--->对象)
-
注意:学框架再学实现
-
-
-
动态代理的分类
-
jdk动态代理(理解)
-
使用Java反射包中的类和接口实现动态代理的功能
-
Java反射包的三个类:InvocationHandler、Method、Proxy
-
-
ogLib动态代理(了解)
-
ogLib是第三方工具库,使用该工具库来创建代理对象
-
ogLib的原理是继承和重写方法。通过继承目标类创建它的子类,在子类中重写父类中同名的方法,实现功能的修改
-
因为ogLib的机制是继承和重写方法,所以要求目标类和方法不能是final的(要求宽松,能继承即可)
-
ogLib在很多框架中使用
-
-
-
Method类的复习(其实是预习)
-
invoke()方法
-
是Method类的一个方法,表示执行方法的调用(用来调用方法)
-
参数:参数1:Object,表示这个对象要执行的方法; 参数2:Object...,方法执行时的参数值
-
返回值:Object,方法执行的返回值
-
-
代码展示
-
纯净版
-
-
public static void main(String[] args) throws Exception {
HelloService target = new HelloServiceImpl();
Method method = HelloService.class.getMethod("sayHello", String.class);
Object ret = method.invoke(target, "李四");
}
-
有注释笔记版
// 使用反射机制执行sayHello方法。核心Method类中的方法
public static void main(String[] args) throws Exception {
// 创建一个需要执行方法的对象
HelloService target = new HelloServiceImpl();
// 获取sayHello名称对应的Method类对象
// 参数1:需要获取的对象的名称(方法名称); 参数2:该方法参数的数据类型
Method method = HelloService.class.getMethod("sayHello", String.class);
// 通过Method对象执行target的sayHello方法
/*
invoke是Method类的一个方法,表示执行方法的调用(用来调用方法)
参数:参数1:Object,表示要执行的方法的对象; 参数2:Object...,方法执行时的参数值
返回值:Object,方法执行的返回值
*/
// 需要执行sayHello方法的对象是target,方法的参数是“李四”(执行target的sayHello方法,参数是“李四”)
Object ret = method.invoke(target, "李四");
}
-
三个类的介绍
-
Java反射包(java.lang.reflect)的三个类:InvocationHandler、Method、Proxy
-
InvocationHandler接口(调用处理器)
-
InvocationHandler接口用来表示代理要干的事情
-
invoke()方法(该接口只有一个方法)
-
invoke()方法表示代理对象要执行的功能代码。代理类要完成的功能写在invoke()方法里面。
-
代理类完成的功能:
-
调用目标方法,执行目标方法的功能
-
功能增强,在目标方法调用时,增加功能
-
-
方法原型:public Object invoke(Object proxt, Method method, Object[] args){...}
-
参数分析:(第一个参数不需要赋值,传递后两个参数即可)
-
Object proxt:jdk创建的代理对象,无需赋值(这个参数不需要我们赋值)
-
Method method:目标类中的方法,jdk提供method对象
-
Object[] args:目标类中方法的参数
-
-
-
使用方式:
-
创建InvocationHandler接口的实现类
-
重写invoke()方法,把要实现的功能写在该方法里
-
-
-
-
Method类
-
Method类用来表示目标类中的方法,可用于调用invoke方法来执行方法
-
作用:通过Method类可以执行某个目标类的方法Method.invoke(目标对象, 方法参数)
-
-
Proxy类
-
Proxy类用来创建代理对象,Proxy类对象是核心的对象。常规创建对象是“new 类的构造方法”,现使用Proxy类的方法来代替new
-
newProxyInstance()静态方法
-
作用:创建代理对象
-
方法原型:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
-
ClassLoader loader:类加载器,负责向内存中加载对象,使用反射获取对象的ClassLoader
-
Class<?>[] interfaces:通过反射获取的目标对象的类所实现的接口
-
InvocationHandler h:代理类要完成的功能,我们自己写(就是InvocationHandler接口的实现类,重写的invoke方法包含了要实现的功能)
-
返回值:代理对象
-
-
-
-
-
实现动态代理的步骤
-
创建接口,定义目标类要完成的功能
-
创建目标类实现接口
-
创建InvocationHandler接口的实现类,在invoke()方法中完成代理类的功能
-
调用目标方法
-
增强功能
-
-
使用Proxy类的静态方法创建代理对象,并把代理对象转为接口类型
-
代码展示
-
创建接口
-
-
package com.bjpowenode.service;
// 目标接口
public interface UsbSell {
//
float sell(int amount);
}
-
创建目标类实现接口
package com.bjpowenode.factory;
import com.bjpowenode.service.UsbSell;
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
System.out.println("目标类中,执行sell目标方法");
return 85.0f;
}
}
-
创建InvocationHandler接口的实现类
package com.bjpowenode.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 实现InvocationHandler接口,完成代理类要做的功能(调用目标方法、功能增强)
public class MySellHandler implements InvocationHandler {
private Object target = null;
// 动态代理:目标对象是活动的,不是固定的,需要传入进来。传入谁,就给谁创建代理
public MySellHandler(Object target){
// 给目标对象赋值
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 定义一个变量,等会接受执行方法时的返回值
Object res = null;
// 执行目标方法,获取返回值
res = method.invoke(target, args); // 执行目标方法
// 加价
if (res != null) {
Float price = (Float)res;
price = price + 25;
res = price;
}
// 在目标类的方法调用后,实现其他功能,即功能增强
System.out.println("您获得一个返利红包");
// 返回加价后的价格
return res;
}
}
-
创建代理对象,并执行功能
package com.bjpowenode;
import com.bjpowenode.factory.UsbKingFactory;
import com.bjpowenode.handler.MySellHandler;
import com.bjpowenode.service.UsbSell;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class MsinShop {
public static void main(String[] args) {
// 使用Proxy类的静态方法创建代理对象,并把代理对象转为接口类型
// 1、创建目标对象
UsbSell factory = new UsbKingFactory();
// 2、创建InvocationHandler对象
InvocationHandler handler = new MySellHandler(factory);
// 3、创建代理对象。
// getClass()方法是获取对象的类, getInterfaces()方法是获取类所实现的接口
// getClassLoader()方法是获取这个类的加载器(类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。)
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
handler);
// 4、通过代理执行方法
float price = proxy.sell(1);
System.out.println("通过动态代理对象调用方法:" + price);
}
}
-
注意
-
jdk动态代理,必须有接口,目标类型实现接口,没有接口时,需要使用cglib动态代理
-