Java两种动态代理

    技术2022-07-10  147

    一. jdk动态代理

    1. jdk动态代理实现原理

    jdk动态代理是jdk原生就支持的一种代理方式,它的实现原理,就是通过让目标类和代理类实现同一接口,代理类持有目标类对象,来达到方法拦截的作用,这样通过接口的方式有两个弊端,一个是必须保证target类有接口,第二个是如果想要对target类的方法进行代理拦截,那么就要保证这些方法都要在接口中声明,实现上略微有点限制。 jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler处理。 代 理 类 必 须 实 现 I n v o c a t i o n H a n d l e r 接 口 , 并 且 , J D K 动 态 代 理 只 能 代 理 实 现 了 接 口 的 类 , 没 有 实 现 接 口 的 类 是 不 能 实 现 J D K 动 态 代 理 。 \color{red}{代理类必须实现InvocationHandler接口,并且,JDK动态代理只能代理实现了接口的类,没有实现接口的类是不能实现JDK动态代理。} InvocationHandlerJDKJDK 结合下面案例代码来看就比较清晰了。

    2.案例

    接口:

    public interface Dongwu { void pao(); void zou(); }

    接口实现类 :

    public class Dog implements Dongwu{ @Override public void pao() { System.out.println("pao===="); } @Override public void zou() { System.out.println("zou===="); } }

    代理增强类:

    public class ProxyHandler implements InvocationHandler { private Object object; public ProxyHandler(Object object){ this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Exception { before(); Object invoke = method.invoke(object, args); after(); return invoke; } // 生成代理类 public Object CreatProxyedObj() { return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new ProxyHandler(object)); } public void after(){ System.out.println("之后处理。。。。。。。。"); } public void before(){ System.out.println("之前处理。。。。。。。。"); } }

    测试类:

    public class Test { public static void main(String[] args) { Dongwu dog = new Dog(); Dongwu o = (Dongwu)new ProxyHandler(dog).CreatProxyedObj();// 强制转换类型必须是接口 o.pao(); } }

    打印结果: 步骤总结:

    1、编写需要被代理的类和接口(我这里就是OrderServiceImpl、OrderService);

    2、编写代理类(例如我这里的DynamicLogProxy),需要实现InvocationHandler接口,重写invoke方法;

    3、使用Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)动态创建代理类对象,通过代理类对象调用业务方法。

    二.cglib动态代理:

    1. cglib实现原理

    基于操作字节码,通过加载代理对象的类字节码,为代理对象创建一个子类,并在子类中拦截父类方法并织入方法增强逻辑。底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的。

    2. 案例

    在上面几个类的基础上新加了一个没有实现接口的类 新加类:

    public class Person { public void eat(){ System.out.println("吃饭"); } public void pao(){ System.out.println("pao"); } }

    cjlib代理类:

    public class ProxyHandler implements MethodInterceptor { private Object object; public void before(){ System.out.println("之前处理。。。。。。。。"); } public void after(){ System.out.println("之后处理。。。。。。。。"); } public ProxyHandler(Object object){ this.object = object; } public Object CreatProxyedObj() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.object.getClass()); // 设置回调方法 enhancer.setCallback(this); // 返回代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object result = methodProxy.invokeSuper(o, objects); after(); return result; } }

    3. 测试

    public class Test { public static void main(String[] args) { Person per = new Person(); Person o= (Person)new ProxyHandler(per).CreatProxyedObj(); o.pao(); } }

    打印结果:

    三.两种动态代理总结:

    1.使用JDK动态代理,目标类必须实现的某个接口,如果 某 个 类 没 有 实 现 接 口 \color{red}{某个类没有实现接口} 则不能生成代理对象。 2.CGLIB通过继承的方式进行代理、无论目标对象没有没实现接口都可以代理,但是 无 法 处 理 f i n a l \color{red}{无法处理final} final的情况(final修饰的方法不能被覆写) 3.性能方面:JDK > CGLIB

    Processed: 0.010, SQL: 9