Java的动态代理,在日常开发中可能并不经常使用,但是并不代表他不重要。Java的动态代理的最主要的用途就是应用在各种框架中。因为使用动态代理可以很方便的运行期生成代理类,通过代理类可以做很多事情,比如AOP,比如过滤器、拦截器等。
在我们平时使用的框架中,像servlet的filter、包括spring提供的aop以及struts2的拦截器都使用了动态代理功能。我们日常看到的mybatis分页插件,以及日志拦截、事务拦截、权限拦截这些几乎全部由动态代理的身影。
而在java中,我们知道有两种实现动态代理的方式:
1、JDK动态代理:Java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。只能对实现了接口的类生成代理,不能针对类。
package com.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义一个用户接口
interface UserService {
void sayHelloWord();
}
// 实现接口的类
class UserServiceImpl implements UserService {
@Override
public void sayHelloWord() {
System.out.println("Hello World!");
}
}
// 实现 java动态代理InvocationHandler 接口
class UserInvocationHandler implements InvocationHandler {
private Object target;
public UserInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoking sayHelloWord()");
Object result = method.invoke(target, args);
System.out.println("After invoking sayHelloWord()");
return result;
}
}
//JDK动态代理demo类
public class JdkDynamicProxyDemo {
public static void main(String[] args) {
// 创建被代理对象
UserService userService = new UserServiceImpl();
// 创建 InvocationHandler接口 对象
InvocationHandler handler = new UserInvocationHandler(userService);
// 创建动态代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
handler);
// 通过代理对象调用目标方法
proxy.sayHelloWord();
}
}
2、Cglib动态代理:Cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。针对类进行代理。对指定的类生成一个子类,覆盖其中的方法。(注意对应的方法不要声明为final,否则无法重写)主要通过Enhancer+ Callback来实现。
package com.demo;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 定义一个用户接口
interface StudentService {
void studyHelloWord();
}
// 实现接口的类
class StudentServiceImpl implements StudentService {
@Override
public void studyHelloWord() {
System.out.println("Study Hello World!");
}
}
class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before method: " + method.getName());
// 执行目标方法
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("After method: " + method.getName());
return result;
}
}
public class CglibProxyDemo {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
StudentServiceImpl studentServiceImpl = (StudentServiceImpl) cglibProxy.getProxy(StudentServiceImpl.class);
// 调用代理对象的方法,实际上会调用MyMethodInterceptor的intercept方法
studentServiceImpl.studyHelloWord();
}
}
这里也分享一下,在实际项目开发过程中可以使用java动态代理的场景:
1、日志记录:通过动态代理,可以在调用被代理类的方法时增加日志记录的逻辑,以便于追踪和调试。
2、事务管理:在调用被代理类的方法之前和之后,可以增加事务管理的逻辑,以确保数据的一致性。
3、权限控制:通过动态代理,可以在调用被代理类的方法之前进行权限验证,以控制用户对资源的访问。
4、RPC远程调用:通过网络将本地对象的方法调用转化远程调用。比如dubbo框架。