一,jdk动态代理:(下面说的构造器是个人理解比喻,不是构造方法)
首先需要知道一个类和一个接口Proxy,InvocationHandler
代理类建造方法
1.Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
参数:ClassLoader loader:任意对象的类加载器 .getClass().getClassLoader()
Class<?>[] interfaces:全部的接口,一般是接口实现类的实例.getClass().getInterfaces()
InvocationHandler h:代理类的构造器对象
代理类构造器
2.InvocationHandler接口只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
参数:Object proxy:指被代理的对象。
Method method:要调用的方法,一般固定语句使用method.invoke(代理对象类,参数).来调用需要调用的方法
Object[] args:方法调用时所需要的参数
我们需要的:
1.代理类构造器(类,创造代理的工具)(InvocationHandler的实现类,其invoke方法参数为固定的,其中method的invoke方法不是此invoke方法。由Proxy类使用反射调用,我们不需要调用)
2.代理类建造方法(方法,中介创建者):Proxy.newProxyInstance(代理接口的类加载器,代理接口,代理类构造器对象--就是1) 该方法可写在代理类构造器中
3.接口(房子)
4.实现接口的类 即被代理对象(房东)
使用步骤:
1.先创建代理类构造器(InvocationHandler接口的实现类),重写接口中invoke方法,
其中method.invoke(被代理的对象,参数),来调用需要调用的方法。我们可以在此上下增强原方法的功能
(就是代理对象被创建出来后,调用方法时,该method通过反射获取你的方法,可以method.getName()获取调用的方法名,使用method.invoke()调用该方法)
2.可以将代理类建造方法Proxy.newProxyInstance写在代理类构造器中,封装为getProxy方法,返回Object类型代理对象,使用时强转类型,这时参数为(任意对象.class.getClassLoader,接口(两种写法,一种是直接写接口.class,一种是实现类.class.getInterfaces()),代理类构造器(this))
public class ProxyInvocationHandler implements InvocationHandler {
//被代理接口/对象
private Object object;
//测试是否为任意对象的类加载器都可以作为参数
private User user = new User();
//构造方法
public ProxyInvocationHandler(Object object) {
this.object = object;
}
public Object getProxy(){
return Proxy.newProxyInstance(
user.getClass().getClassLoader(),
object.getClass().getInterfaces(),
this);
}
//反射方法,method可以获取被代理对象调用的方法,进行一些操作
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println("调用前,调用的方法为:"+name);
Object res = method.invoke(object,args);
System.out.println("调用后,调用的方法为:"+name);
return res;
}
}
3.测试类中
a.创建被代理对象。
b.创建代理类构造器,并将被代理对象传参给它。
c.使用代理类构造器创建代理类,因为得到的是Object类型,所以需要强转类型。
d.调用方法。
public class Test {
public static void main(String[] args) {
//被代理对象
landlord landlord = new landlord();
//代理类构造器
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(landlord);
//创建代理类
Host host= (Host) proxyInvocationHandler.getProxy();
host.sellHost();
}
}
结果
调用前,调用的方法为:sellHost
房东卖房
调用后,调用的方法为:sellHost
Cglib动态代理
Cglib是针对实现类来代理的,被代理者不需要实现接口,它对目标类生成一个子类,并覆盖其中的方法,以实现方法的增强。
cglib的主要方法拦截接口 MethodInterceptor,需要用户自己实现:
public interface MethodInterceptor extends Callback {
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}
参数说明:
前三个参数与jdk中InvocationHandler中的Invoke相同:
Object var1:指被代理的对象。
Method var2:要调用的方法
Object[] var3:方法调用时所需要的参数MethodProxy var4: JDK的java.lang.reflect.Method类的代理类,可以实现对源对象方法的调用。后面的例子将会帮助理解。
Enhancer:cglib主要的增强类,下面简单看下其中方法:
setSuperclass: 设置被代理的对象。
setCallback: 设置回调函数,一般为MethodInterceptor的实现类。
creat: 创建一个代理对象,你可以直接使用创建的代理对象调用原本的方法。
看个实例:
public class MyCglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("----------before----"+method.getName());
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("----------after----"+method.getName());
return o1;
}
}
之前说了,cglib是创建一个子类,并覆盖目标类方法,所以我们调用方法时,是使用methodProxy.invokeSuper()。我们在每个方法之前之后都输出一些语句。
测试代码:
MyCglibInterceptor myCglibInterceptor=new MyCglibInterceptor();
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(myInterface.getClass());
enhancer.setCallback(myCglibInterceptor);
MyInterface res = (MyInterface) enhancer.create();
res.getName();
res.getAge();
结果:
----------before----getName
tom
----------after----getName
----------before----getAge
11
----------after----getAge
参考文档:
尚硅谷-Spring5框架最新版教程(idea版)_哔哩哔哩_bilibili