jdk动态代理和cglib动态代理
Posted ghghg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk动态代理和cglib动态代理相关的知识,希望对你有一定的参考价值。
静态代理就不说了...
jdk动态代理
- 在java中动态代理主要有一个接口InvocationHandler和Proxy
- 实现InvocationHandler接口的并不是代理类,他主要封装了调用方法,invoke(ClassLoader,Interfaces[],InvocationHandler),以加载器作为参数是因为在java中只有类加载器和类相同的两个对象才是同一类对象(即使是同一个类new出来的,但类加载器不同,这两对象是不同Class的对象),接口作为参数,主要是想获取接口中的方法定义,InvocationHandler可以获取到被代理的对象(获取到this的所有field就可以获取注入的被代理类),InvocationHandler并不是代理类.
-
public interface Student { void learn(); void playGame(); }
公共接口
-
public class Hg implements Student { @Override public void learn() { System.out.println("hg爱学习"); } @Override public void playGame() { System.out.println("hg爱玩游戏"); } }
被代理的类
-
public class HgHandler implements InvocationHandler { private Object obj=null; public Object getProxy(Object obj){ this.obj=obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this); } //proxy是代理对象的参数,这个参数并不能直接转为代理类接口,但可以返回,因此可以连续调用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("learn")){ System.out.println("爱学习吗?"); } if(method.getName().equals("playGame")){ System.out.println("还敢打游戏?"); } Object invoke = method.invoke(obj, args); return null; } }
在这里注意:注入被代理对象是必须的,因为invoke方法中需要使用,而getProxy是非必须的,可以推迟到client中newInstance(),而且在方法中并没有使用proxy,那不由得产生疑问,那这个proxy放在这有啥作用呢,了解后发现,他虽然不能直接使用,但是他可以作为返回值返回,因此可以链式调用(即objProxy.learn().playGame();那如果我们利用proxy是代理这一特性在invoke中强转为Student后,不就可以直接使用了吗,看下图
-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Student hg=(Student)proxy; hg.playGame(); return null; }
结果发现堆栈溢出,这是什么操作,仔细想想,就是目前proxy还没有确定自己所代理的对象,然后又将他强转为Student,而代理又去找自己的代理,无限找下去,当然会溢出了
cglib动态代理
- jdk动态代理是jdk自带的,而cglib是依赖第三方库
-
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
- cglib动态代理主要有两部分,MethodInterceptor(方法拦截器)和Enhancer(提高器)在方法拦截器中被代理对象的方法进行包装,增强
-
//cglib通过继承父类,并覆盖父类的方法来实现代理父类,所以一个类被final修饰, // 则该类不能被代理,一个方法被final修饰,则该方法不能贝被覆盖 public class Person { public void dance(){ System.out.println("person 爱跳舞"); } public final void drink(){ System.out.println("person 喝水"); } }
-
MyMethodInterceptor类
-
public class MyMethodInterceptor implements MethodInterceptor { /** * * @param o cglib生成的代理对象 * @param method 被代理对象方法 * @param objects 方法入参 * @param methodProxy 代理方法 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("前置检查"); Object o1 = methodProxy.invokeSuper(o, objects); System.out.println("后置检查"); return o1; } }
method在方法中并没有使用,使用了被代理对象的invokeSuper的methodProxy方法,增强
- 测试类
-
public class TestCglib { public static void main(String[] args) { Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(Person.class); enhancer.setCallback(new MyMethodInterceptor()); Person per = (Person)enhancer.create(); per.dance(); per.drink(); } }
- 执行结果
- 可见喝水由于是final修饰的,得不到增强,如果将Person类用final修饰,将会在运行时报错
//cglib通过继承父类,并覆盖父类的方法来实现代理父类,所以一个类被final修饰,
// 则该类不能被代理,一个方法被final修饰,则该方法不能贝被覆盖
public class Person {
public void dance(){
System.out.println("person 爱跳舞");
}
public final void drink(){
System.out.println("person 喝水");
}
}
以上是关于jdk动态代理和cglib动态代理的主要内容,如果未能解决你的问题,请参考以下文章