2020最新更新-jdk动态代理
1、什么是动态代理
使用jdk的反射机制,创建对象的能力,创建的是代理类的对象。不用你创建文件,不用写java文件。
动态:是指,在程序执行时,调用jdk提供的方法才能创建代理类的对象
在程序的执行过程中使用jdk的反射机制,创建代理类对象,并动态的指定要代理的目标类
动态代理是一种创建java对象的能力,让你不用自己创建对象,就能代理类创建对象。
2、实现方式
cglib动态代理(第三方的工具库,原理是继承,通过继承目标类,创建他的子类,在子类中重写父类中同名的方法,实现功能的修改,所以要求目标类不能是final的。
在很多框架中使用,mybatis和spring中都有使用,对于无接口的类,需要使用这种方式)
===========================================
jdk动态代理(必须有接口)
jdk动态代理:使用jdk反射提供的类和接口实现动态代理的功能。
相关接口和类的详细讲解
java,lang.reflect包下的三个类:InvocationHandler、Method、Proxy
InvocationHandler接口(调用处理器):就一个方法invoke(),表示代理对象要执行的功能代码,你的代理类要完成的功能就在这个方法中
怎么用InvocationHandler
创建一个类实现InvocationHandler,重写invoke()
public Object invoke(Object proxy, Method method, Object[] args)
- Object proxy:jdk创建的代理对象,无需赋值。
- Methos:目标类中的方法,jdk中提供的method对象的
- Object[] args:目标类中方法的参数
Method类:表示方法的,确切的说是目标类的方法
作用:通过Method可以执行某个目标类方法,核心方法为invoke()
Method.invoke()
public Object invoke(Object obj, Object… args)
public Object invoke(目标对象,方法的参数)
Proxy类:创建代理对象。之前都是创建对象都是new类的构造方法,现在是用Proxy类的方法,代替new的使用
方法:静态方法 newProxyInstance()
作用是创建代理对象,等同于代理中 A a = new A();
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- ClassLoader:类加载器,负责向内存中加载对象,使用反射获取对象的ClassLoader
获取ClassLoader利用反射如下
a.getClass().getClassLoader() (目标对象的类加载器) - Class<?>[] interfaces:目标对象实现的接口,也是反射获取的 a.getClass().getInterfaces()
- InvocationHandler:我们自己写的,代理类要完成的功能
3、动态代理能做什么
可以在不改变原来目标方法的功能前提下,可以在代理中增强自己的功能代码,达到功能增强
4、示例代码用来理解上面的概念
注意:jdk代理必须要有接口才能使用
- 接口
public interface UserDao {
//所谓增强就是在已经写好的代码基础上进行功能扩展,但是又不在原来代码上改动,这个时候代理就有用了
public int query(String name);
}
- 实现类
public class UserDaoImp implements UserDao {
@Override
//我就是目标类,代理类就是来增强我的,我返回2,但是最终结果想返回4,我可以在代理类中修改我的结果
public int query(String name) {
System.out.println("我是目标类的输出");
return 2;
}
}
- 代理类
public class UserDaoProxy implements InvocationHandler {
//这个就是用构造方法获取目标类就是上面的UserDao
private Object target;
public UserDaoProxy(Object target){
this.target = target;
}
//重写InvocationHandler接口的invoke方法,代理对象要执行的功能代码,你的代理类要完成的功能就在这个方法中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 这里可以做增强 可在目标方法之前执行你要增强的内容 也可以在后面
System.out.println("我是前面====");
//通过Method类利用目标对象获取你要增强的方法
Object result = method.invoke(target, args);
if(result!=null){
Integer num = (Integer)result;
result = num*2;
}
return result;
}
}
- 测试方法
public class Main {
public static void main(String[] args) {
//目标对象
UserDao user = new UserDaoImp();
//代理对象
UserDaoProxy invocationHandler = new UserDaoProxy(user);
//通过Proxy类创建代理对象
UserDao proxy = (UserDao) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), invocationHandler);
//返回结果肯定是代理类中已经乘以2的结果 4
Integer res = proxy.query("33333");
System.out.println("期望的返回结果=="+res);
proxy.add();
}
}
- 查看测试结果