1、基本概念
- 动态代理允许我们在运行时根据指定的接口动态地创建代理对象,这个代理对象与目标对象实现了相同的接口,因此可以完全替代目标对象执行相同的操作。
- 通过动态代理,我们可以在不修改目标对象代码的情况下,为目标对象添加额外的功能或逻辑。
- JDK动态代理和CGLIB动态代理是Java中两种常见的动态代理实现方式,它们各自有不同的特点和适用场景。
2、原理
- 动态代理的实现原理主要基于Java的反射机制。
- 在运行时,动态代理会根据指定的接口创建一个代理类,并在代理类中重写接口中的所有方法。
- 当代理对象调用接口方法时,实际执行的是代理类中的对应方法。
- 在代理类中,我们可以通过反射机制调用目标对象的方法,并在执行前后添加自己的逻辑。
3、应用场景
- 动态代理在Spring框架中得到了广泛应用,主要用于实现AOP(面向切面编程)功能。
- AOP是一种编程范式,用于处理系统中散布于各个模块之间的交叉关注点问题,如事务管理、日志记录、安全控制等。
- 通过动态代理,Spring可以在运行时为目标对象创建代理对象,并在代理对象中织入切面逻辑,从而实现对这些交叉关注点问题的统一处理。
4、常见实现方式
4.1 JDK动态代理
4.1.1简介
- JDK动态代理是Java标准库提供的一种动态代理实现方式,它基于Java的反射机制。
- JDK动态代理只能代理实现了接口的类,通过动态生成代理类来实现对目标对象的代理。
- 在JDK动态代理中,代理类是由Java运行时环境动态生成的,每个代理类都会实现与被代理对象相同的接口。
- 通过使用Proxy、Method、InvocationHandler类库来完成动态代理
- JDK动态代理的优点是简单易用,因为它是Java标准库的一部分,无需引入额外的依赖。
4.1.2代码示例
步骤1:先创建UserService接口
java
public interface UserService {
void save();
void delete();
}
步骤2:创建一个接口的实现类UserServiceImpl(目标类对象)
java
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("主业务逻辑:增加用户管理");
}
@Override
public void delete() {
System.out.println("主业务逻辑:删除用户管理");
}
}
步骤3:创建动态代理(InvocationHandler接口的实现类)
java
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
public MyInvocationHandler(Object obj){
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
System.out.println("开始监控系统...");
long t1 = System.currentTimeMillis();//当前时间
try {
Thread.sleep((int) (Math.random() * 2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
Object o = method.invoke(obj, args);
long t2 = System.currentTimeMillis();//当前时间
System.out.println("结束监控系统...");
System.out.println("一共耗费了" + (t2 - t1) + "毫秒");
//加日志处理
System.out.println(LocalDate.now() + "访问系统");
return o;
}
}
步骤4:使用Proxy,创建代理对象
java
public class ProxyUtil {
public static Object getProxy(Object target, InvocationHandler handler)
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
}
}
步骤5:测试
java
public static void main(String[] args) {
UserService service= new UserServiceImpl();
UserService proxy = (UserService) ProxyUtil.getProxy(service,
new MyInvocationHandler(service));
proxy.save();
System.out.println("------------------------------------");
proxy.delete();
}
}
4.2 CGLIB动态代理
4.2.1简介
- CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以扩展Java类和实现Java接口。
- 与JDK动态代理不同,CGLIB动态代理是通过继承目标类来创建代理对象的,因此它可以代理没有实现接口的类。
- CGLIB动态代理底层使用ASM(一个Java字节码操控和分析框架)来操作字节码生成新的类,为对象引入间接级别,以控制对象的访问。
- CGLIB动态代理的优点在于它可以代理没有实现接口的类,提供了更多的灵活性。
- CGLIB动态代理不能对final类及final方法进行代理。
4.2.2代码示例
步骤1:创建目标类
java
public class AccountService {
public void save(){
System.out.println("保存账务管理业务");
}
public void pay(){
System.out.println("支持管理业务");
}
}
步骤2:编写增强类
java
public class MyInterceptor implements MethodInterceptor {
private Object obj;
public MyInterceptor(Object obj) {
this.obj = obj;
}
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("进入系统");
Object invoke = method.invoke(obj, objects);
System.out.println(LocalDate.now());
return invoke;
}
}
步骤3:测试
java
public class Test {
public static void main(String[] args) {
AccountService service = new AccountService();
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(AccountService.class.getClassLoader());
enhancer.setSuperclass(AccountService.class);
enhancer.setCallback(new MyInterceptor(service));
AccountService accountService = (AccountService) enhancer.create();
accountService.save();
System.out.println("------------------------------");
accountService.pay();
}
}