Java 动态代理
目录
一、动态代理是什么
二、动态代理的实现原理
2.1 JDK 动态代理
2.2 CGLIB 动态代理
三、动态代理的应用场景
家人们,今天咱来聊聊 Java 里特别神奇的动态代理,这可是让代码灵活性和扩展性大幅提升的 “秘密武器”。很多厉害的 Java 框架都离不开它,理解并掌握它,能让你在 Java 编程的道路上更进一步。
一、动态代理是什么
想象一下,你要去买房子,但自己没时间,就找了个房产中介。中介帮你找房源、谈价格、办手续,你只需要告诉中介你的需求,剩下的事都由中介来处理。在 Java 里,动态代理就像这个中介,它可以在不修改目标对象代码的情况下,为目标对象添加额外的功能。比如在方法执行前记录日志,在方法执行后进行事务提交等。动态代理基于反射机制实现,在运行时动态创建代理对象,为我们的代码赋予了极大的灵活性。
二、动态代理的实现原理
Java 中实现动态代理主要有两种方式:JDK 动态代理和 CGLIB 动态代理。
2.1 JDK 动态代理
JDK 动态代理是 Java 自带的动态代理实现方式,它只能为实现了接口的类创建代理对象。JDK 动态代理主要涉及两个核心类:Proxy
和InvocationHandler
。
Proxy
:用于创建代理对象,它提供了一个静态方法newProxyInstance()
,通过这个方法可以创建一个代理对象。这个方法接收三个参数:类加载器、目标对象实现的接口数组、实现了InvocationHandler
接口的对象。InvocationHandler
:是一个接口,它定义了一个invoke()
方法。当通过代理对象调用方法时,实际上会调用invoke()
方法,在这个方法中我们可以添加额外的逻辑,然后再调用目标对象的方法。
下面是一个 JDK 动态代理的示例代码:
// 定义一个接口
interface HelloService {
void sayHello();
}
// 实现接口的类
class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
System.out.println("Hello, world!");
}
}
// 定义一个InvocationHandler实现类
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前的额外逻辑,比如记录日志");
Object result = method.invoke(target, args);
System.out.println("方法调用后的额外逻辑,比如事务提交");
return result;
}
}
public class JDKProxyExample {
public static void main(String[] args) {
HelloService target = new HelloServiceImpl();
HelloService proxy = (HelloService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvocationHandler(target));
proxy.sayHello();
}
}
在这个示例中,我们创建了一个HelloService
接口和实现该接口的HelloServiceImpl
类。然后定义了MyInvocationHandler
类,实现了InvocationHandler
接口,在invoke()
方法中添加了方法调用前后的额外逻辑。最后使用Proxy.newProxyInstance()
方法创建代理对象,通过代理对象调用sayHello
方法时,就会执行我们添加的额外逻辑。
2.2 CGLIB 动态代理
CGLIB(Code Generation Library)是一个第三方的代码生成库,它可以为没有实现接口的类创建代理对象。CGLIB 通过继承目标类,创建一个子类,在子类中重写父类的方法,从而实现代理功能。使用 CGLIB 需要引入相应的依赖。
下面是一个 CGLIB 动态代理的示例代码:
<!-- 在Maven项目中添加CGLIB依赖 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
// 没有实现接口的类
class UserService {
public void addUser() {
System.out.println("添加用户");
}
}
// 定义一个MethodInterceptor实现类
class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法调用前的额外逻辑");
Object result = proxy.invokeSuper(obj, args);
System.out.println("方法调用后的额外逻辑");
return result;
}
}
public class CGLIBProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new MyMethodInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.addUser();
}
}
在这个示例中,我们定义了一个没有实现接口的UserService
类。然后创建了MyMethodInterceptor
类,实现了MethodInterceptor
接口,在intercept()
方法中添加了额外逻辑。最后使用Enhancer
类创建代理对象,设置代理对象的父类为UserService
,并设置回调函数为MyMethodInterceptor
。通过代理对象调用addUser
方法时,就会执行我们添加的额外逻辑。
三、动态代理的应用场景
动态代理在很多 Java 框架中都有广泛应用,比如在 Spring AOP(面向切面编程)中,动态代理是实现 AOP 的核心技术之一。通过动态代理,Spring 可以在不修改目标对象代码的情况下,为目标对象添加事务管理、日志记录、权限控制等功能。在 MyBatis 框架中,动态代理也用于创建 Mapper 接口的代理对象,实现 SQL 语句的执行和结果映射。
家人们,动态代理虽然有点难理解,但一旦掌握,就能让你的代码变得超级灵活强大。要是在学习过程中有什么疑问,随时找我交流,咱们一起把这个技术吃透!