JDK动态代理

目录

动态代理

动态代理核心类

细节测试案例


动态代理

动态代理灵活性很大。在任意时候任意地方都可以使用代理功能(前提是该对象有接口)

可以代理有接口的实现类,也可以直接代理接口(代理接口的话,接口往往配合注解加入一些信息,然后代理去解析)

动态代理核心类

/**
 * 1.动态代理可以代理任何类(前提是此类有实现的接口,没有实现接口不可以被jdk代理)
 * 2.将被代理的对象传入getProxy,就会得到它的代理(必须用传入的对象所实现的任何一个接口接收)
 * 3.调用代理的任何方法==调用InvocationHandler的invoke方法。

 * 应用场景举例1:
 *  比如service层ServiceImpl每个数据库的交互的方法里面都只写核心代码即可 ,
    而将serviceImpl传 入此代里类getProxy方法生成代理(用service接口接收),
    用返回的代理service去保 存修改(不用原来的service),
    则一旦用返回的代理调用方法就会执行InvocationHandler的invoke 里面的代码。
    自然而然的建立连接,然后执行被代理对象(serviceImpl )的核心代码,然后自动提交事务,最后关闭 连接 

 */
public class DynamicProxy {
    /**
     * 1.Proxy.newProxyInstance参数介绍:
     * 第一个参数是被代理对象的类加载器,负责将字节码文件装在到虚拟机
     * 第二个参数是被代理的对象所实现的接口,生成的代理也会实现被代理对象实现的所有接口
     * 第三个参数是实现了InvocationHandler的实例
     * 2.InvocationHandler中invoke方法参数介绍:
     * Object proxy:Proxy.newProxyInstance返回的对象,通常不用(用了很可能造成死循环)
     * Method method:当前被调用方法
     * Object[] args:当前被调用方法的参数
     * 3.InvocationHandler中invoke返回值:表示当前被调用方法的返回值
     * 
     * 
     * @param t
     * @param <T>
     * @return
     */
    public static <T> T getProxy(T t) {
        return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //调用目标方法之前做的公共逻辑
                System.out.println("建立连接");
                //调用目标方法,这句话必须要有的,就是调用被传入的对象的方法(里面写了核心代码)
                Object object = method.invoke(t, args);
                //调用目标方法之后做的公共逻辑
                System.out.println("提交事务");
                System.out.println("关闭连接");
                return object;
            }
        });
    }
}

测试

public class TestDynamicProxy {
    @Test
    public void test() {
        //创建被代理的对象
        UserMapper userMapper = new UserMapper();
        //通过代理类获取代理对象(必须用接口接收)
        MapperInterface userMapperProxy = DynamicProxy.getProxy(userMapper);
        //调用代理的save方法,会进入Invocation的invoke方法。
        userMapperProxy.save(new User());
    }
}

运行结果:

细节测试案例

  1. 没有实现任何接口的类不能被jdk代理
  2. 生成的代理对象只能用接口接收及原因
  3. 生成的代理对象继承了Proxy
  4. InvocationHandler的invoke里面调用proxy造成死循环

 1.没有实现接口的类不能被jdk代理

/**
 * 1.没有实现接口的类不能被jdk代理
 */
public class TestDynamicProxy {
    @Test
    public void test1() {
        //标准的jdk基于接口代理,user2没有实现的接口,所以不可以被代理,下面运行会报错
        User2 user2 = DynamicProxy.getProxy(new User2("ss"));
        System.out.println("---->" + user2.getClass());
    }

    @Test
    public void test2() {
        //不用User2接收,直接获取代理也报同样的错误
        System.out.println("---->" + DynamicProxy.getProxy(new User2("ss")).getClass());
    }
}

运行结果:

2.生成的代理对象只能用接口接收

/**
 * 可以被代理的对象回来的代理只能用接口(被代理的对象实现的任何一个接口都可以)接收
 */
public class TestDynamicProxy {
    @Test
    public void test1() {
        //studentMapper实现了MapperInterface和MyInterface
        StudentMapper studentMapper = new StudentMapper();
        //用实现的接口MapperInterface接收
        MapperInterface studentMapperProxy = DynamicProxy.getProxy(studentMapper);
        //用实现的接口MyInterface接收
        MyInterface myInterface = DynamicProxy.getProxy(studentMapper);
        System.out.println("---->" + studentMapperProxy.getClass());
        System.out.println("---->" + myInterface.getClass());
        myInterface.sout();
    }

}

/**
 *不能用实现类接收的原因:
 * class com.sun.proxy.$Proxy2不可以被转换----》class com.blog.staticproxy.StudentMapper
 */
public class TestDynamicProxy {
    @Test
    public void test1() {
        StudentMapper studentMapper = new StudentMapper();
        MapperInterface studentMapperProxy = DynamicProxy.getProxy(studentMapper);
        //---->class com.sun.proxy.$Proxy2
        System.out.println("---->" + studentMapperProxy.getClass());
        //class com.blog.staticproxy.StudentMapper
        System.out.println(studentMapper.getClass());
    }
}


/**
 * 可以用接口接收的原因:代理对象实现了接口,是接口的一个实例。当然可以接收
 * 运行结果:----->com.blog.staticproxy.MapperInterface
 *          ----->com.blog.staticproxy.MyInterface
 */
public class TestDynamicProxy {
    @Test
    public void test1() {
        StudentMapper studentMapper = new StudentMapper();
        MapperInterface studentMapperProxy = DynamicProxy.getProxy(studentMapper);
        Class<?>[] interfaces = studentMapperProxy.getClass().getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("----->"+anInterface.getName());
        }
    }
}

3. 生成的代理对象继承了Proxy

  @Test
    public void test1() {
        StudentMapper studentMapper = new StudentMapper();
        MapperInterface studentMapperProxy = DynamicProxy.getProxy(studentMapper);
        Class<?> superclass = studentMapperProxy.getClass().getSuperclass();
        //java.lang.reflect.Proxy
        System.out.println(superclass.getName());
    }

4.InvocationHandler的invoke里面调用proxy造成死循环

 /**
     * 首先调用代理对象的任何方法==调用InvocationHandler的invoke
     * 比如调用代理对象的save,进入到InvocationHandler的invoke
     * 执行到下面method.invoke(proxy, args)又要调用InvocationHandler的invoke故造成了死循环
     */
    public static <T> T getProxy(T t) {
        return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object object = method.invoke(proxy, args);
                return object;
            }
        });
    }

 /**
     * 通过看代理对象源码,不仅代理里了接口里面的方法,
     *还默认代理了toString,hashCode,equals方法(在方法里面有super.h.invoke()即调用Proxy里InvocationHandler里面的invoke)
     * 所以调用toString,hashCode,equals任意一个==InvocationHandler的invoke造成死循环
     * 没有代理getClass,所以在nvocationHandler的invoke里调用getClass不会死循环
     */
    public static <T> T getProxy(T t) {
        return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(proxy.getClass());
//                System.out.println(proxy.toString());
//                System.out.println(proxy.hashCode());
//                System.out.println(proxy.equals(t));
                Object object = method.invoke(t, args);
                return object;
            }
        });
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值