动态代理
# JDK动态代理
代理类和被代理类都能转化为 接口类型,它们是平级关系;
核心:InvocationHandler 接口
和 Proxy 类
Proxy类用于生成代理的方法:
- 第一个参数:运行期间生成字节码,所以第一个参数需要类加载器加载运行期间动态生成的字节码;
- 第二个参数:要实现哪个接口数组;
- 第三个参数:具体代理类的实现由InvocationHandler实现;
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
}
/*
loader :类加载器,用于加载代理对象。
interfaces : 被代理类实现的一些接口;
h : 实现了 InvocationHandler 接口的对象;
*/
2
3
4
5
6
7
8
9
10
11
12
当动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler
接口类的 invoke
方法来调用。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
/*
proxy :动态生成的代理类
method : 与代理类对象调用的方法相对应
args : 当前 method 方法的参数
*/
2
3
4
5
6
7
8
通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。
使用步骤:
- 定义一个接口及其实现类;
- 自定义
InvocationHandler
并重写invoke
方法,在invoke
方法中调用原生方法(被代理类的方法)并自定义一些处理逻辑; - 通过
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象;
案例:
自定义接口与实现类:
public interface SmsService { String send(String message); }
1
2
3public class SmsServiceImpl implements SmsService{ @Override public String send(String message) { System.out.println("send message: " + message); return message; } }
1
2
3
4
5
6
7自定义JDK动态代理类
public class DebugInvocationHandler implements InvocationHandler { /*类代理中的真实对象*/ private final Object target; public DebugInvocationHandler(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; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17获取代理对象的工厂类
public class JdkProxyFactory { public static Object getProxy(Object target){ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DebugInvocationHandler(target) ); } }
1
2
3
4
5
6
7
8
9测试类
public class Test { public static void main(String[] args) { SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("java"); } }
1
2
3
4
5
6before method send send message:java after method send
1
2
3
面试题:jdk动态代理为什么需要基于接口?
追问:jdk动态代理要求代理类实现InvocationHandler接口,重写invoke方法就可以实现动态代理,且构造函数注入Object即可,并无要求Object必须基于接口,而且重本质上说getProxy()获代理类(Object的原类),完全可以通过继承对象的方式?
源码剖析:
获取代理类的是:getProxyClass0
继续追get方法,最终看到调用到ProxyClassFactory类的apply()方法
在ProxyClassFactory的apply方法中真正的代理类的方法:generateProxyClass
发现只需要将saveGeneratedFiles设置true,即可本地查看生成的代理类:
修改测试代码:
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
smsService.send("java");
}
2
3
4
5
本地多了一个代理类:$Proxy0本身就继承了一个Proxy类,由于java不支持多继承,因此无法实现动态代理
总结:生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口实现。
# CGLIB动态代理
通过父子继承关系创建代理,代理作为子类型,可以转换为父类型,父类和方法上都不能加final(代理毕竟是继承或重写);
被代理类
class UserDao{
public void saveUser(){
sout("新增用户");
}
}
2
3
4
5
增强类
class MyAspect{
public void check_permission(){
sout("检查权限");
}
public void log(){
sout("日志记录");
}
}
2
3
4
5
6
7
8
代理类
class CglibProxy implements MethodInterceptor{
//被代理类
private Object target;
public Object createProxy(Object target){
this.target = target;
//通过cglib增强代码
Enhancer enhancer = new Enhancer();//生成代理的工厂类
//生成目标类对象的子类进行增强
//设置被代理类的类型type
enhancer.setSuperclass(target.getClass());
//增强后回调
enhancer.setCallback(this);
Object proxy = enhancer.create();
return proxy;
}
//如何增强父类
//proxy:代理对象 引用
//method:被代理对象的方法描述引用
//args:方法参数
//methodProxy:代理对象 对目标对象的方法的描述
@Override
public Object intercept(Object proxy,Method method,Object[] args,MehtodProxy methodProxy) thorows Throwable{
//增强代码
MyAspect aspect = new MyAspect();
aspect.check_permission();
//调用原始方法
//1.代理类对象进行调用
Object invokeSuper = methodProxy.invokeSuper(proxy,args);
//2.原对象
//Object invoke = method.invoke(target,args);
return invokeSuper;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
测试类
main{
//原对象
UserDao target = new UserDao();
//new proxy工厂类实例
CglibProxy cglibProxy = new CglibProxy();
UserDao proxy = (UserDao)cglibProxy.createProxy(target);
proxy.saveUser();
}
2
3
4
5
6
7
8