动态代理是实现AOP的基础,这篇文章向你说明什么是动态代理。
在做日志、性能监控、权限检查等功能的时候,我们通常会用到AOP,AOP的底层是动态代理。动态代理的实现有两种方式:一种是基于JDK,一种是基于第三方库cglib。访问的时候,直接访问代理对象,再由代理对象对实际对象对象进行访问。我们熟悉的用Nginx反向代理也是这样的原理,请求会经过Nginx转发给后面的Tomcat服务。使用代理的好处是:我们可以在访问实际对象方法的前后添加处理逻辑,如:权限校验,而不用修改实际访问方法的逻辑。
静态代理
静态代理是指我们手动创建代理类,生成代理对象。使用代理后,在不修改原类的情况下,在实际对象的方法调用前后加一些语句。如下面的例子:
public class ProxyDemo {
static interface IService {
void doSomething();
}
static class RealServiceImpl implements IService {
@Override
public void doSomething() {
System.out.println("do something");
}
}
static class ProxyServiceImpl implements IService {
private IService realService;
public ProxyServiceImpl(IService realService) {
this.realService = realService;
}
@Override
public void doSomething() {
System.out.println("entering");
this.realService.doSomething();
System.out.println("leaving");
}
}
public static void main(String[] args) {
IService realService = new RealServiceImpl();
IService proxyService = new ProxyServiceImpl(realService);
proxyService.doSomething();
}
}
动态代理
使用动态代理,可以编写通用的代理逻辑,用于各种类型的被代理对象,而不需要为每个被代理的类型都创建一个静态代理类。在静态代理中,代理类是直接定义在代码中的,在动态代理中,代理类是动态生成。我们可以看到JDK动态代理只能代理接口,由JVM根据接口的定义动态生成代理类
JDK动态代理
public class JDKProxyDemo {
static interface IService {
void doSomething();
}
static class RealServiceImpl implements IService {
@Override
public void doSomething() {
System.out.println("do something");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("entering");
Object result = method.invoke(realObj, args);
System.out.println("leaving");
return result;
}
}
public static void main(String[] args) {
IService realService = new RealServiceImpl();
IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(),
new Class<?>[]{IService.class}, new SimpleInvocationHandler(realService));
proxyService.doSomething();
}
}
cglib动态代理
如果被代理的对象没有实现任何接口,那么就无法使用JDK动态代理,这时候可以考虑使用cglib动态代理。
public class SimpleDemo {
static class RealService {
public void doSomething() {
System.out.println("do something");
}
}
static class Interceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("entering" + method.getName());
Object result = methodProxy.invokeSuper(object, args);
System.out.println("leaving" + method.getName());
return result;
}
}
private static <T> T getProxy(Class<T> cls) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new Interceptor());
return (T) enhancer.create();
}
public static void main(String[] args) {
RealService proxyService = getProxy(RealService.class);
proxyService.doSomething();
}
}
个人博客:https://www.kangpeiqin.cn/#/index