Java代理详解

Java代理详解

1. 静态代理

1.1 实现方式

  1. 为每个需要被代理的类都写一个对应的代理类,并实现目标类中想要代理的方法接口
  2. 创建代理对象时,通过构造器放入一个目标对象作为成员变量
  3. 实现被代理的方法,根据需要处理添加业务逻辑

1.2 代码示例

public class StaticProxyDemo {

    public static void main(String[] args) {
        // 一般在bean注入时用代理对象替换掉被代理的对象, 所以代理时一般以接口维度处理
        DemoInterface demoInterface = new DemoProxy(new DemoImpl());
        demoInterface.say();
    }

    /**
     * 接口
     */
    public interface DemoInterface {
        void say();
    }

    /**
     * 被代理类
     */
    public static class DemoImpl implements DemoInterface {
        @Override
        public void say() {
            System.out.println("impl");
        }
    }

    /**
     * 静态代理类
     */
    public static class DemoProxy implements DemoInterface {
        private final DemoInterface demoInterface;
        public DemoProxy(DemoInterface demoInterface) {
            this.demoInterface = demoInterface;
        }

        @Override
        public void say() {
            System.out.println("proxy before");
            demoInterface.say();
            System.out.println("proxy after");
        }
    }

}

1.3 静态代理的缺点

  1. 手动编写目标类:如果是针对单个对象的特殊逻辑还好,但如果是希望针对大范围的代理,工作量就会很大,代码也很臃肿
  2. 修改不便:当代理的对应接口出现调整时,代理类也需要跟随调整,即使调整的逻辑跟代理类的逻辑完全没关系

使用代理的场景基本是为了实现一些通用逻辑,个性化逻辑大部分情况下没必要使用代理来处理。

2. JDK动态代理

2.1 实现方式

Java内置的一种代理方式,通过反射来在运行时动态地创建代理类。

JDK动态代理要求目标对象必须实现接口。

实现流程:

  1. 实现InvocationHandler接口 或 使用Proxy类生成代理类对象
  2. 利用反射执行代理类中的方法

2.2 代码示例

import java.lang.reflect.*;

public class JdkProxyDemo {

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        DemoInterface demoInterface = (DemoInterface) JdkProxyDemo.getProxy(new DemoImpl());
        System.out.println(demoInterface.say());

        DemoInterface demoInterface2 = (DemoInterface) JdkProxyDemo.getInvocationHandlerProxy(new DemoImpl());
        System.out.println(demoInterface2.say());
    }

    /**
     * 接口
     */
    public interface DemoInterface {
        String say();
    }

    /**
     * 被代理类
     */
    public static class DemoImpl implements DemoInterface {
        @Override
        public String say() {
            return "impl";
        }
    }

    /**
     * Proxy对象代理
     *
     * @param proxyTarget 被代理对象
     * @return 代理对象
     */
    public static Object getProxy(Object proxyTarget) {
        return Proxy.newProxyInstance(
                // 类加载器, 无特殊情况使用与目标对象相同的类加载器
                proxyTarget.getClass().getClassLoader(),
                // 代理对象实现的接口, 一般与代理对象保持一致, 保证所有接口方法被代理
                proxyTarget.getClass().getInterfaces(),
                (proxy1, method, args) -> {
                    System.out.println(method.getName() + "JDK Proxy Before");
                    Object result = method.invoke(proxyTarget, args);
                    System.out.println(method.getName() + "JDK Proxy After");
                    return result;
                }
        );
    }

    /**
     * Proxy对象代理
     *
     * @param proxyTarget 被代理对象
     * @return 代理对象
     */
    public static Object getInvocationHandlerProxy(Object proxyTarget) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> proxyClazz = Proxy.getProxyClass(proxyTarget.getClass().getClassLoader(), proxyTarget.getClass().getInterfaces());
        Constructor<?> constructor = proxyClazz.getConstructor(InvocationHandler.class);
        return constructor.newInstance((InvocationHandler) (proxy1, method, args) -> {
            System.out.println(method.getName() + "JDK InvocationHandler Proxy Before");
            Object result = method.invoke(proxyTarget, args);
            System.out.println(method.getName() + "JDK InvocationHandler Proxy After");
            return result;
        });
    }

}

3. CGLIB动态代理

CGLIB代理(Code Generation Library)是一个高性能代码生成库。可以创建各种类型代码,其中包含了代理。

在代理方面,CGLIB代理不要求目标对象实现接口,因此它的使用范围更广,不过性能相比JDK动态代理要差一点(但不多)

CGLIB 动态代理的实现机制是生成目标类的子类,通过调用父类(目标类)的方法实现,在调用父类方法时在代理中进行增强。

PS:由于是继承方式实现的,所以final类和final方法无法被代理

实现流程:

  1. 导入CGLIB依赖包;
  2. 代理类实现MethodInterceptor
  3. 使用Enhancer类得到动态代理的实例,并执行指定方法

4. Javassist动态代理

Javassist是一个用于操作Java字节码的指令库,可以分析、编辑和创建Java字节码,通过对.class文件的修改,实现对类的修改和创建。

一般在开发中不会用到,主要是用于封装框架,比如struts2和hibernate。

Javassist动态代理主要有以下两种方式:

  1. 代理工厂创建:实现MethodHandler,处理代理逻辑,与CGLIB类似
  2. 动态代码创建:通过Java代码,分析class文件结构,动态的去创建代理代码,可以在运行时生成业务逻辑
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值