什么是动态代理
要知道什么是动态代理,相对的,我们首先要了解什么是静态代理,
静态代理解析连接https://blog.youkuaiyun.com/qq_42051306/article/details/114107743
从静态代理我们知道,代理的功能主要有两点:
1. 隐藏我们需要代理的类(也就是原有的类,需要去代理的类,叫做被代理类)
2. 既然要隐藏我们的被代理类,就不能去改变原有类的代码,在此基础上,通过代理我们还可以添加其他功能,叫做功能增强
静态代理实现了代理的功能,下面我们需要的动态代理是为了改进静态代理的缺点
动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
我们依然通过代码来了解动态代理的一个过程,既然是代理,那么我们依然采用JDK动态代理方式,接口、类的形式
主题接口
public interface UserDao {
void add();
}
实现类
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("add...");
}
}
注意这里就没有像动态代理一样的代理类了,因为我们的代理类是通过Java反射的方式来生成,是动态获取
public class Test {
public static void main(String[] args) {
UserDaoImpl user = new UserDaoImpl();
UserDao instance = (UserDao) getProxyInstance(user);
instance.add();
}
public static Object getProxyInstance(Object obj){
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
创建动态代理对象的主要过程是使用Proxy类中的newProxyInstance()方法
、
该方法有三个参数
第一个叫做类加载器:
这个参数我们在调用的时候应该怎么填?--------由于代理类是需要去代理原有的类的,因此类加载器也应该和原有类的类加载器相同
因此在原有对象的基础上通过反射得到类加载器填入第一个参数user.getClass().getClassLoader()
第二个参数叫做接口:
由于类可以实现多个接口,因此这个参数是一个数组类型,此处的接口就是我们原有类实现的接口
也是通过对象通过反射的方式获取原有类实现的接口user.getClass().getInterfaces()
第三个参数叫做处理者:
这是最关键的一个参数,通过文档我们可以看到这个参数需要一个InvocationHandler的对象
既然没有就需要创建一个对象,而又发现InvocationHandler是个接口,因此我们需要自己创建这个接口的一个实现类
class MyInvocationHandler implements InvocationHandler{
private Object obj;
public void bind(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("增强之前");
Object o = method.invoke(obj, args);
System.out.println("增强之后");
return o;
}
}
通过这个实现类来创建一个对象,实现里面的一个抽象方法invoke();
这个方法就是代理的主要方法,当我们通过newProxyInstance()方法创建的代理类调用原有的add方法时,就会自动的调用invoke()方法
怎么通过这个方法来调用原有的add方法呢,我们可以看到在invoke方法中有三个参数
第一个参数proxy:
这个参数其实就是我们产生的代理对象,其实在平时的使用中,这个参数基本上使用不到,关于参数详情请看https://blog.youkuaiyun.com/yaomingyang/article/details/81040390
第二个参数method:
这个参数其实就是我们要增强的方法,也就是需要代理类去调用的方法,通过这个参数调用invoke()方法
method.invoke(Object obj, Object... args)
这个方法有两个参数需要 填写,
1. 第一个参数就是我们需要代理的类的对象,
定义为private Object obj;
创建bindf()方法为该属性赋值,调用的时候传入一个真正的对象即可,
2. 第二个参数就是我们需要调用的方法的参数,是个可变形参,根据实际方法的参数来确定,invoke()方法中的第三个参数(注意这里的两个invoke()并不相同)
最后结果可以为
希望对动态代理不熟悉的人有所帮助