美文网首页
Java代理模式及动态代理详解

Java代理模式及动态代理详解

作者: robertzhai | 来源:发表于2023-12-13 06:58 被阅读0次

jdk 动态代理

  • JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。
public interface Sell {
    void sell();
    void ad();
}

public class Vendor implements Sell{
    @Override
    public void sell() {
        System.out.println("Shop sell goods");
    }

    @Override
    public void ad() {
        System.out.println("Shop advert goods");

    }
}

package com.company;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

public class LogHandler implements InvocationHandler {

    Object target;  // 被代理的对象,实际的方法执行者
    public LogHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target, args);  // 调用 target 的 method 方法
        after();
        return result;  // 返回方法的执行结果
    }

    // 调用invoke方法之前执行
    private void before() {
        System.out.println("log start");
    }
    // 调用invoke方法之后执行
    private void after() {
        System.out.println("log end ");
    }
}



package com.company;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {
    // write your code here

        // 创建中介类实例
        LogHandler logHandler = new LogHandler(new Vendor());
        // 设置该变量可以保存动态代理类,默认名称$Proxy0.class
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 获取代理类实例Sell
        Sell sell = (Sell) (Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[]{Sell.class}, logHandler));
        // 通过代理类对象调用代理类方法,实际上会转到invoke方法调用
        sell.sell();
        sell.ad();
    }
}

output

log start
Shop sell goods
log end 
log start
Shop advert goods
log end 

cglib

  • Cglib动态代理采用的是创建目标类的子类的方式。优点:不用实现额外接口,只操作我们关心类,高性能。基于ASM机制实现,通过生成业务类的子类作为代理类。
<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version> 
</dependency>


public class UserDao {

    public void findAllUsers(){
        System.out.println("UserDao findAllUsers");
    }

    public String findUsernameById(int id){
        System.out.println("UserDao findUsernameById");
        return "findUsernameById";
    }
}


import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


public class LogInterceptor implements MethodInterceptor {

    /**
     *
     * @param obj 表示要进行增强的对象
     * @param method 表示拦截的方法
     * @param objects 数组表示参数列表,基本数据类型需要传入其包装类型,如int-->Integer、long-Long、double-->Double
     * @param methodProxy 表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用
     * @return 执行结果
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before(method.getName());
        // 注意这里是调用invokeSuper而不是invoke,否则死循环;
        // methodProxy.invokeSuper执行的是原始类的方法;
        // method.invoke执行的是子类的方法;
        Object result = methodProxy.invokeSuper(obj, objects);
        after(method.getName());
        return result;
    }

    /**
     * 调用invoke方法之前执行
     */
    private void before(String methodName) {
        System.out.println("调用方法" + methodName +"之【前】的日志处理");
    }

    /**
     * 调用invoke方法之后执行
     */
    private void after(String methodName) {
        System.out.println("调用方法" + methodName +"之【后】的日志处理");
    }
}

import net.sf.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {

        // 通过CGLIB动态代理获取代理对象的过程
        // 创建Enhancer对象,类似于JDK动态代理的Proxy类
        Enhancer enhancer = new Enhancer();
        // 设置目标类的字节码文件
        enhancer.setSuperclass(UserDao.class);
        // 设置回调函数
        enhancer.setCallback(new LogInterceptor());
        // create方法正式创建代理类
        UserDao userDao = (UserDao) enhancer.create();
        // 调用代理类的具体业务方法
        userDao.findAllUsers();
        userDao.findUsernameById(1);
    }
}


output

调用方法findAllUsers之【前】的日志处理
UserDao findAllUsers
调用方法findAllUsers之【后】的日志处理
调用方法findUsernameById之【前】的日志处理
UserDao findUsernameById
调用方法findUsernameById之【后】的日志处理

Process finished with exit code 0

ref

相关文章

网友评论

      本文标题:Java代理模式及动态代理详解

      本文链接:https://www.haomeiwen.com/subject/nwjbgdtx.html