什么是动态代理?我来告诉你!

什么是动态代理

动态代理是一种在运行时创建代理对象的机制,它可以用于在不修改原始类的情况下,在运行时添加额外的功能。代理对象对外表现为原始类的实例,但实际上所有对代理对象的方法调用都会被重定向到特定的处理器(也称为代理处理器)执行。

动态代理的工作原理是通过反射机制来实现的。当我们需要创建一个代理对象时,需要提供一个接口或者类,然后定义一个代理处理器,该处理器实现了InvocationHandler接口。在代理对象被调用方法时,代理处理器的invoke方法会被触发,并可以在该方法中实现对原始方法的增强、记录日志、进行权限控制等操作。

动态代理的优点在于它可以在运行时动态地创建代理对象,并且可以对不同的对象使用同一个代理处理器,从而实现对多个对象的统一处理。它可以用来实现一些横切关注点(cross-cutting concerns),例如日志记录、性能监控等,从而提升代码的复用性和可维护性。
动态代理结构如下图:
在这里插入图片描述
动态代理中用的比较多的两种创建代理对象的方法:
//JDK动态代理

Proxy.newProxyInstance(三个参数);

//CGLib动态代理

Enhancer.create(两个参数);

JDK动态代理

使用JDK官方的java.lang.reflect.Proxy类的newProxyInstance方法实现的代理。
JDK动态代理实列代码:

public interface Subject {
    void doSomething();
}
 	/**
     * 生成对象的代理对象,对被代理对象进行所有方法日志增强
     * 参数:原始对象
     * 返回值:被代理的对象
     * JDK 动态代理
     *  基于接口的动态代理
     *  被代理类必须实现接口
     *  JDK提供的
     */
class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject: Doing something.");
    }
}


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

class ProxyHandler implements InvocationHandler {
    private Subject realSubject;

    public ProxyHandler(Subject realSubject) {
        this.realSubject = realSubject;
    }
		/**
         * 创建对象的代理对象
         * 参数一:类加载器
         * 参数二:对象的接口
         * 参数三:调用处理器,代理对象中的方法被调用,都会在执行方法。对所有被代理对象的方法进行拦截
         */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用真实对象之前可以进行一些其他操作
        System.out.println("ProxyHandler: Before calling doSomething()");

        // 调用真实对象的方法
        Object result = method.invoke(realSubject, args);

        // 在调用真实对象之后可以进行一些其他操作
        System.out.println("ProxyHandler: After calling doSomething()");

        return result;
    }
}


import java.lang.reflect.Proxy;

class Main {
    public static void main(String[] args) {
        // 创建一个真实对象
        Subject realSubject = new RealSubject();

        // 创建代理处理器
        ProxyHandler handler = new ProxyHandler(realSubject);

        // 创建代理对象
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);

        // 通过代理对象调用方法
        proxySubject.doSomething();
    }
}

CGLib动态代理

实现CGLib动态代理:
需从CGLib的官方网站(https://github.com/cglib/cglib)下载CGLib,然后将cglib-nodep-{version}.jar文件添加到你的项目中。
接下来,创建一个原始类RealSubject,不需要实现接口:

public class RealSubject {
    public void doSomething() {
        System.out.println("RealSubject: Doing something.");
    }
}

然后,创建一个代理类ProxySubject:

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

import java.lang.reflect.Method;

public class ProxySubject implements MethodInterceptor {
    private Object realSubject;

    public ProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }

    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(realSubject.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
	/**
     * 重写方法拦截在方法前和方法后加入业务
     * Object obj为目标对象
     * Method method为目标方法
     * Object[] params 为参数,
     * MethodProxy proxy CGlib方法代理对象
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    	//参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。
        //返回:从代理实例的方法调用返回的值。
        //其中,proxy.invokeSuper(obj,arg) 调用代理类实例上的proxy方法的父类方法(即实体类TargetObject中对应的方法)

        // 在调用真实对象之前可以进行一些其他操作
        System.out.println("ProxySubject: Before calling doSomething()");

        // 调用真实对象的方法
        Object result = proxy.invokeSuper(obj, args);

        // 在调用真实对象之后可以进行一些其他操作
        System.out.println("ProxySubject: After calling doSomething()");

        return result;
    }
}

最后,编写测试代码:

public class Main {
    public static void main(String[] args) {
        // 创建一个真实对象
        RealSubject realSubject = new RealSubject();

        // 创建代理对象
        ProxySubject proxySubject = new ProxySubject(realSubject);
        RealSubject proxy = (RealSubject) proxySubject.createProxy();

        // 通过代理对象调用方法
        proxy.doSomething();
    }
}

浅聊AOP原理

  1. AOP 思想

它旨在解决横切关注点(cross-cutting concerns)与核心业务逻辑之间的分离和耦合问题,通过在不修改目标对象代码的情况下,通过代理对象的方式,将横切关注点应用到目标对象的特定方法或代码段。

  1. AOP 作用

在不修改源代码的情况下,可以增加额外的功能,实现在原有功能基础上的增强。

  1. AOP 使用场景
  • 记录日志(调用方法后记录日志)
  • 监控性能(统计方法运行时间)
  • 权限控制(调用方法前校验是否有权限)
  • 事务管理(调用方法前开启事务,调用方法后提交关闭事务 )
  • 缓存优化(第一次调用查询数据库,将查询结果放入内存对象, 第二次调 用,直接从内存对象返回,不需要查询数据库 )
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值