java动态代理-面向对象的补充

代理类是指在程序运行十创建的,可以根据调用处理器生成任何想要的结果。我们可以把面向对象理解为一个静态的过程,那么java动态代理就是面向对象的补充和完善。

动态代理demo

定义接口和实现类

public interface ProductDao {
    void add();

    void update();

    void search();

    void delete();
}

public class ProductDaoImpl implements ProductDao {
    @Override
    public void add() {
        System.out.println("商品新增add");
    }

    @Override
    public void update() {
        System.out.println("商品修改update");
    }

    @Override
    public void search() {
        System.out.println("商品搜索search");
    }

    @Override
    public void delete() {
        System.out.println("商品删除delete");
    }
}

实现代理工厂

public class JdkProxyFactory implements InvocationHandler {
    public Object target;

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

    public Object createProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before(method);
        Object result = method.invoke(target, args);
        after(method);
        return result;
    }

    private void after(Method method) {
        // 目标方法执行后记录日志
        System.out.println("日志记录:" + method.getName() + "执行结束了...");
    }

    private void before(Method method) {
        // 目标方法执行前记录日志
        System.out.println("日志记录:" + method.getName() + "开始执行了...");
    }
}

测试类

public class JdkProxyFactoryTest {
    public static void main(String[] args) {
        ProductDaoImpl productDao = new ProductDaoImpl();
        ProductDao proxyInstance = (ProductDao) new JdkProxyFactory(productDao).createProxyInstance();
        //当执行这个方法时会执行代理方法,在方法前后增加日志
        proxyInstance.add();
    }
}

生成的代理类

类信息动态生成的二进制字节码保存到硬盘中

public class ProxyUtils {
    public static void generateClassFiles(Class clazz,String proxyName){
    	/*
    	* params: clazz 需要生成动态代理类的类
     	* proxyName: 为动态生成的代理类的名称
    	*/
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String path = clazz.getResource(".").getPath();
        System.out.println("path = " + path);

        FileOutputStream out = null;
        try{
            out = new FileOutputStream(path + proxyName + ".class");
            out.write(classFile);
            out.flush();
        }catch (Exception e){

        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

测试类增加

ProxyUtils.generateClassFiles(productDao.getClass(),"proxyProductDao");

生成的代理类

在target包的相对路径下

public final class proxyProductDao extends Proxy implements ProductDao {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m5;
    private static Method m6;
    private static Method m0;
    private static Method m4;

    public proxyProductDao(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void add() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void delete() throws  {
        try {
            super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void search() throws  {
        try {
            super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void update() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.my.dao.ProductDao").getMethod("add");
            m5 = Class.forName("com.my.dao.ProductDao").getMethod("delete");
            m6 = Class.forName("com.my.dao.ProductDao").getMethod("search");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m4 = Class.forName("com.my.dao.ProductDao").getMethod("update");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通过这个代理类可以了解到以下几点

  • JDK动态代理的目标类必须实现某个接口,这是由他的实现机制决定的
  • 代理类的仅有一个构造函数,且唯一参数是InvocationHandler接口,这是给开发者自己实现的。
  • 代理类执行方法时,可以直观看到实际上是执行的是自己是实现的invoke方法

源码解析

动态代理的实现依赖两个关键类
Proxy.newProxyInstance(ClassLoader classLoader,Interface[] interfaces,InvocationHandler h):构造实现指定接口的代理类的一个新实例,所有方法会调用给定处理器对象的 invoke 方法
InvocationHandler:定义了代理对象调用方法时希望执行的动作,用于集中处理在动态代理类对象上的方法调用

//简化代码
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        final Class<?>[] intfs = interfaces.clone();
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
        	//获取构造函数
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //反射获取对象
            return cons.newInstance(new Object[]{h});
        } 
    }

总结

优点:

  • 动态代理减少了重复代码,提高了代码的可维护性和可读性。
  • 通过动态代理,可以在不修改原始代码的情况下添加新的功能,如日志记录、性能监控等。
    缺点:
  • 动态代理基于反射机制,可能会影响性能。
  • 无法代理final类或方法,也无法代理static方法。
  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值