Proxy代理详解:什么是java动态代理

动态代理有以下特点:
1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理


JDK中生成代理对象的API
代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:

  • ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的

  • Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型

  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入


这里,我们定义一个接口类:UserDao以及它的实现类UserDaoImpl一个不实现任何接口User类。它们均拥有保存用户的save方法。同时,再定义一个用户动态代理对象:ProxyFactory,让我们来看看实际的应用场景:

代码示例:

接口类:UserDao

package com.codedocs.net.proxy;
/**
 * 接口类
 */
public interface UserDao {
    void save();
}

实现类:UserDaoImpl

package com.codedocs.net.proxy;
/**
 * 目标类
 */
public class UserDaoImpl implements UserDao {

    @Override
    public void save() {
        System.out.println("保存用户信息");
    }

}

无接口类:User

package com.codedocs.net.proxy;

public class User {

    public void save() {
        System.out.println("(不使用接口)保存用户");
    }
}

动态代理类:ProxyFactory

package com.codedocs.net.proxy;

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

/**
 * 动态代理对象(代理对象不需要像静态代理那样实现接口)
 */
public class ProxyFactory{

    /**
     * 目标对象(目标对象一定要实现接口,否则会报错)
     */
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("动态代理开启事务");
                        Object returnValue = method.invoke(target, args);
                        System.out.println("动态代理提交事务");
                        return returnValue;
                    }
                }
        );
    }
    
    public static void main(String[] args) {
        /** 目标对象UserDaoImpl实现了UserDao接口能正确的执行  */
         // 目标对象
        UserDao target = new UserDaoImpl();
        System.out.println(target.getClass());
        // 动态的创建代理对象
        UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
        // 内存中动态生成的代理对象
        System.out.println(proxy.getClass());
        // 保存用户
        proxy.save();
        
        /** 目标对象User未实现任何接口,执行失败 */
        User taget = new User();
        User userProxy = (User) new ProxyFactory(taget).getProxyInstance();
        userProxy.save();
    }

}

代码执行结果:

class com.codedocs.net.proxy.UserDaoImpl
class $Proxy0
动态代理开启事务
保存用户信息
动态代理提交事务
Exception in thread "main" java.lang.ClassCastException: $Proxy1 cannot be cast to com.codedocs.net.proxy.User
    at com.codedocs.net.proxy.ProxyFactory.main(ProxyFactory.java:50)

总结:
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理、执行报错。

评论

*
*