Java 代理模式 复习

95 阅读3分钟

Java 设计模式之代理模式 -- 复习

静态代理和动态代理的 Java 实现方式

关于代理模式的基本概念就不在此处描述了,本文主要是根据简单的代码实现静态和动态代理

静态代理主要通过代理类注入被代理对象,然后调用代理对象方法前后实现增强
动态代理则是有两种方式:JDK API 和 CGLIB
前者被代理类必须实现接口,后者不用但是被代理类不可被final修饰,被代理方法不可被final修饰

静态代理:
静态代理的实现方式比较简单,代理类注入被代理对象,然后在执行被代理对象方法前后设置需要增强的内容

// 静态代理

// 接口
interface SmsService {
    void sendMsg(String msg);
}

// 实现类
class SmsServiceImpl implements SmsService {

    @Override
    public void sendMsg(String msg) {
        System.out.println("发送邮件: " + msg);
    }
}

// 静态代理类, 注意此处使用了lombok插件生成构造函数
@AllArgsConstructor
@NoArgsConstructor
class SmsProxy implements SmsService {
    private SmsService smsService;

    // 注入被代理对象,然后静态实现增强
    @Override
    public void sendMsg(String msg) {
        System.out.println("发送邮件前...");
        smsService.sendMsg(msg);
        System.out.println("发送邮件后...");
    }

    // 测试方法
    public static void main(String[] args) {
        SmsProxy proxy = new SmsProxy(new SmsServiceImpl());
        proxy.sendMsg("早上好!");
    }
}

// 输出结果
发送邮件前...
发送邮件: 早上好!
发送邮件后...

动态代理: JDK API 方式

// 动态代理 JDK API 方式

// 被代理接口
interface SmsService {
    void sendMsg(String msg);
}

// 被代理实现类
class SmsServiceImpl implements SmsService {

    @Override
    public void sendMsg(String msg) {
        System.out.println("发送每日邮件: " + msg);
    }
}

// 代理handler,此处完成代理, 注意此处使用了lombok插件和注解生成构造函数
@NoArgsConstructor
@AllArgsConstructor
class JDKProxyHandler implements InvocationHandler {

    // 注入被代理对象
    private SmsService smsService;

    // 代理
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("发送邮件前...");
        // 第一个参数是被代理对象
        // 第二个参数是执行方法的参数
        Object result = method.invoke(smsService, args);
        System.out.println("发送邮件后...");
        return result;
    }
}

// 生成代理对象的工厂
class JDKProxyFactory {
    public static SmsService getInstance(SmsService smsService) {
        return (SmsService) 
        // 该方法三个参数分别为:
        // 1.被代理类的接口类对象的类加载器
        // 2.被代理类的接口类对象的字节码
        // 3.实现了InvocationHandler接口的子类
        Proxy.newProxyInstance(smsService.getClass().getClassLoader(),
                smsService.getClass().getInterfaces(),
                new JDKProxyHandler(smsService));
    }
}

class Main {
    // 测试
    public static void main(String[] args) {
        SmsService instance = JDKProxyFactory.getInstance(new SmsServiceImpl());
        instance.sendMsg("早安!");
    }
}

动态代理: cglib 方式

// 动态代理 CGLIB 方式

// 被代理类,可不实现接口
class SmsServiceImpl {
    public void sendMsg(String msg) {
        System.out.println("发送每日邮件:" + msg);
    }
}

// 代理处理handler
class CglibProxyHandler implements MethodInterceptor {

    // 此处实现代理
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理之前...");
        // 注意此处和JDK代理的不同,方法是使用MethodProxy执行
        // 且调用的方法为invokeSuper而不是invoke
        // 并且代理对象直接是方法参数o,不需要手动注入了
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("cglib代理之后...");
        return result;
    }
}

// 工厂
class CglibProxyFactory {
    public static SmsServiceImpl getInstance(SmsServiceImpl smsService) {
        // 通过Enhancer对象实现代理
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(smsService.getClass().getClassLoader());
        // 设置字节码
        enhancer.setSuperclass(smsService.getClass());
        // 设置回调方法(代理类)
        enhancer.setCallback(new CglibProxyHandler());
        // 生成代理对象并返回
        return (SmsServiceImpl) enhancer.create();
    }
}

// 测试类
class Main {
    public static void main(String[] args) {
        SmsServiceImpl instance = CglibProxyFactory.getInstance(new SmsServiceImpl());
        instance.sendMsg("good morning!");
    }
}