什么是动态代理
动态代理是一种在运行时创建代理对象的机制,它可以用于在不修改原始类的情况下,在运行时添加额外的功能。代理对象对外表现为原始类的实例,但实际上所有对代理对象的方法调用都会被重定向到特定的处理器(也称为代理处理器)执行。
动态代理的工作原理是通过反射机制来实现的。当我们需要创建一个代理对象时,需要提供一个接口或者类,然后定义一个代理处理器,该处理器实现了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原理
- AOP 思想
它旨在解决横切关注点(cross-cutting concerns)与核心业务逻辑之间的分离和耦合问题,通过在不修改目标对象代码的情况下,通过代理对象的方式,将横切关注点应用到目标对象的特定方法或代码段。
- AOP 作用
在不修改源代码的情况下,可以增加额外的功能,实现在原有功能基础上的增强。
- AOP 使用场景
- 记录日志(调用方法后记录日志)
- 监控性能(统计方法运行时间)
- 权限控制(调用方法前校验是否有权限)
- 事务管理(调用方法前开启事务,调用方法后提交关闭事务 )
- 缓存优化(第一次调用查询数据库,将查询结果放入内存对象, 第二次调 用,直接从内存对象返回,不需要查询数据库 )