动态代理(jdk&cglib)的用法

什么是代理模式(Proxy)

定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用

在代理模式中,是需要代理对象和目标对象实现同一个接口

为什么要用代理

最最最主要的原因就是,在不改变目标对象方法的情况下对方法进行增强,比如,我们希望对方法的调用增加日志记录,或者对方法的调用进行拦截,等等...

一:JDK动态代理

JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。

案例

1、定义业务接口以及实现类

package com.yjc.jdkproxy;

public interface DoSomeService {
    void doSome();
}
-------------------------------------------

package com.yjc.jdkproxy;

public class DoSomeServiceImpl implements DoSomeService {
    @Override
    public void doSome() {
        System.out.println("doSome++++++++++++++++++==");
    }
}

2.调用管理接口InvocationHandler 创建动态代理类

package com.yjc.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DoSomeHandler implements InvocationHandler {
  //这其实业务实现类对象,用来调用具体的业务方法
    private  Object target;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before----------------------------");
      //调用真正的业务方法 Object invoke
= method.invoke(target, args); System.out.println("after---------------------------"); return invoke; } public DoSomeHandler(Object target) { this.target = target;//接收业务实现类对象参数 } public DoSomeHandler() { } }

测试方法

package com.yjc.jdkproxy;

import sun.misc.ProxyGenerator;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;

public class JdkProxyTest {
    public static void main(String[] args) throws IOException {
        DoSomeService doSomeService=new DoSomeServiceImpl();
     //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
        //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
DoSomeService o
= (DoSomeService)Proxy.newProxyInstance(doSomeService.getClass().getClassLoader(), new Class[]{DoSomeService.class}, new DoSomeHandler(doSomeService));   //调用目标函数
     o.doSome();
      //将内存中代理的类生成到本地
byte[] $proxy0s = ProxyGenerator.generateProxyClass("$proxy0", new Class[]{DoSomeService.class}); FileOutputStream fos=new FileOutputStream("F:/$proxy0.class"); fos.write($proxy0s); fos.flush(); fos.close(); } }

二:CGLIB动态代理

     cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。

 cglib和jdk动态代理的区别就是,cglib无需业务接口也可以实现动态代理,而jdk是在业务接口的基础上进行实现的,没有接口不行。cglib也需要项目对cglib的支持,需要引入依赖

业务类

package com.yjc.cglibproxy;

public class DoSomeServiceImpl {

    public void doSome() {
        System.out.println("doSome++++++++++++++++++==");
    }
}

代理类

package com.yjc.cglibproxy;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DoSomeHandler implements MethodInterceptor {
    //目标对象
    private  Object target;


    public DoSomeHandler(Object target) {
        this.target = target;
    }

    public DoSomeHandler() {
    }

/**
*
* 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法
* 拦截对目标方法的调用
*
* @param obj 代理对象
* @param method 拦截的方法
* @param args 拦截的方法的参数
* @param proxy 代理
* @return
* @throws Throwable
*/

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before==========================");
        Object invoke = method.invoke(target, objects);
        System.out.println("after============================");
        return invoke;
    }
}

测试类

package com.yjc.cglibproxy;

import net.sf.cglib.proxy.Enhancer;

public class CglibProxyTest {
    public static void main(String[] args) {
        Enhancer enhancer=new Enhancer(); 
// 设置目标对象的Class
enhancer.setSuperclass(DoSomeServiceImpl.class); 
  // 设置回调操作,相当于InvocationHandler
enhancer.setCallback(new DoSomeHandler(new DoSomeServiceImpl()));
DoSomeServiceImpl o
=(DoSomeServiceImpl) enhancer.create();
o.doSome();
} }

 

posted @ 2019-10-28 16:34  天戈  阅读(244)  评论(0编辑  收藏  举报