动态代理

什么是动态代理?

在不改变目标对象的前提下,对目标对象进行增强。使用代理对象增强目标对象。在调用目标对象前后,进行增强功能,

增强代码需要我们手动编写。

动态代理产生的过程

创建一个代理对象工厂来生成代理对象。

public class JdkFactory {

    // 根据目标对象生成代理对象
    private Object target;

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

    /**
     * 生成代理对象 ,在这儿生成的是一个代码类。根据代理类生成代理对象。
     * Proxy.newProxyInstance
     * 1. 根据接口生成代理类。所以参数里面需要interface
     * 2.将生成的字节码文件加载到jvm内存中。所以需要类加载器参数
     * 3.生成的java代码类中,有个成员变量 invocationHandler 对目标方法做增强
     * 
     * @return
     */
    public Object getProxy() {

        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new MyInvocationHandler(target));
        return proxy;

    }

}

总结上述步骤:根据接口生成代理类,代理类的成员变量是invocationHandler,将代理类加载到内存中。然后根据Class对象生成代理对象。返回给调用者。

增强类的实现

public class MyInvocationHandler implements InvocationHandler {
    // 目标类对象
    private Object target;

    // 构造方法传入
    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 执行目标对象中的方法,并对目标对象的方法做增强。
        try {
            System.out.println("方法增强。。。。");
            Object result = method.invoke(target, args);
            return result;
        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }

}

测试代码

public class TestProxy {
    @Test
    public void testJdkProxy() {

        // 目标对象
        UserService service = new UserServiceImpl();
        JdkFactory jdkFactory = new JdkFactory(service);
        UserService proxy = (UserService) jdkFactory.getProxy();

        generateProxyClass(proxy);

        service.Save();
        System.out.println("====");
        proxy.Save();

    }
    //生成 的代理类的字节码文件生成,我们可以根据字节码文件反编译看一下生成代理类的构造。
    public void generateProxyClass(UserService proxy) {
        // TODO Auto-generated method stub
        FileOutputStream out = null;
        try {
            byte[] generateProxyClass = ProxyGenerator.generateProxyClass(proxy.getClass().getSimpleName(),
                    new Class[] { proxy.getClass() });
            out = new FileOutputStream(proxy.getClass().getSimpleName() + ".class");
            out.write(generateProxyClass);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                }
            }
        }
    }

}

生成的代理类

public final class $Proxy4 extends Proxy implements com.sun.proxy.$Proxy4
{
// 接口中的方法。和object中的方法。
    private static Method m1;
    private static Method m6;
    private static Method m2;
    private static Method m7;
    private static Method m11;
    private static Method m3;
    private static Method m13;
    private static Method m0;
    private static Method m8;
    private static Method m12;
    private static Method m5;
    private static Method m10;
    private static Method m4;
    private static Method m9;
    //通过构造方法引入增强器,增强器通过构造方法将目标对象引入
    public $Proxy4(final InvocationHandler invocationHandler) {
        super(invocationHandler);
    }
    
    public final boolean equals(final Object o) {
        try {
            //增强器invoke方法,对目标对象进行增强。
            return (boolean)super.h.invoke(this, $Proxy4.m1, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
    

增强器代码

public class MyInvocationHandler implements InvocationHandler {
    // 目标类对象
    private Object target;

    // 构造方法传入
    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 执行目标对象中的方法,并对目标对象的方法做增强。
        try {
            System.out.println("方法增强。。。。");
            Object result = method.invoke(target, args);
            return result;
        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }

}

cglib 动态代理

基于继承的方式来生成字节码文件

增强类

public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib 增强");
        Object returnValue = methodProxy.invokeSuper(proxy, arg);
        return returnValue;
    }

}

生成代理对象的工厂

public class CglibFactory {

    public Object getProxyByCgLib(Class<?> clazz) {

        Enhancer enhancer = new Enhancer(); // 设置需要增强的类的类对象
        enhancer.setSuperclass(clazz); // 设置回调函数
        enhancer.setCallback(new MyMethodInterceptor());
        Object obect = enhancer.create(); // 获取增强之后的代理对象
        generatorClass(enhancer);
        return obect;
    }
    //生成代码类字节码的方法
    private void generatorClass(Enhancer enhancer) {
        FileOutputStream out = null;
        try {
            byte[] bs = DefaultGeneratorStrategy.INSTANCE.generate(enhancer);
            FileOutputStream fileOutputStream = new FileOutputStream("Enhancer_cglib" + ".class");
            fileOutputStream.write(bs);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {

                }
            }
        }

    }

}

测试方法

@Test
    public void testCgLibProxy() {
        // 创建目标对象
        UserService service = new UserServiceImpl();

        // 生成代理对象
        CglibFactory proxyFactory = new CglibFactory();
        UserService proxy = (UserService) proxyFactory.getProxyByCgLib(service.getClass());

        // 调用目标对象的方法
        service.Save();
        System.out.println("===============");
        // 调用代理对象的方法
        proxy.Save();
    }

生成的字节码文件

//看到了继承父类

public class UserServiceImpl$$EnhancerByCGLIB$$3845b6a0 extends UserServiceImpl implements Factory
{
   
   
    public final void Save() {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        //调用了增强器的invoke方法
        if (cglib$CALLBACK_0 != null) {
            cglib$CALLBACK_2.intercept((Object)this, UserServiceImpl$$EnhancerByCGLIB$$3845b6a0.CGLIB$Save$0$Method, UserServiceImpl$$EnhancerByCGLIB$$3845b6a0.CGLIB$emptyArgs, UserServiceImpl$$EnhancerByCGLIB$$3845b6a0.CGLIB$Save$0$Proxy);
            return;
        }
        super.Save();//调用了父类的save方法
    }

动态代理和静态代理区别:
静态代理每次目标类添加方法的时候,代理类对应都要添加,不符合开闭原则
动态代理是动态的去生成代码的方式,我们不用手动去改代理类。符合开闭原则。反射执行方法效率低

cglib 和 jdk 的动态代理区别:
cgib 动态代码 生成代码类 是通过继承目标类的方法
jdk 生成带来类是根据目标类实现的接口来重写方法
cglib 生成字节码的时候,效率低。但是执行的时候效率高
jdk 生成字节码效率高,但是需要反射执行目标方法,效率低

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容