Java 静态代理 vs 动态代理 vs CGLib Proxy

来源:互联网 发布:linux 看目录本身权限 编辑:程序博客网 时间:2024/05/23 16:56

代理:为其他对象提供访问目标对象的一种控制或机制。

接口定义

public interface FontProvider {    Font getFont(String name);}

实现定义

@Slf4jpublic class FontProviderImpl implements FontProvider {    public FontProviderImpl() {        log.info("FontProviderImpl Constructor");    }    @Override    public Font getFont(String name) {        log.info("ready to call getFont()");        return new Font(name, Font.ITALIC, 18);    }}

代理定义

  • 静态代理
@Slf4jpublic class FontProviderSimpleProxy implements FontProvider {    private FontProvider fontProvider;    public FontProviderSimpleProxy(FontProvider fontProvider) {        this.fontProvider = fontProvider;    }    public Font getFont(String name) {        log.info("ready to call getFont in FontProviderSimpleProxy, args is {}", name);        return fontProvider.getFont(name);    }}
  • JDK动态代理
@Slf4jpublic class FontProviderDynamicProxy implements InvocationHandler {    private Object target;    public FontProviderDynamicProxy(Object target) {        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        log.info("ready to call getFont in FontProviderDynamicProxy, args is {}", args);        Type[] types = method.getParameterTypes();        if (method.getName().matches("get.+") && (types.length == 1) &&                (types[0] == String.class)) {            return method.invoke(target, args);        }        return method.invoke(target, args);    }}
  • CGLib动态代理
@Slf4jpublic class FontProviderCGLibProxy implements MethodInterceptor {    public <T> T getProxy(Class<T> cls) {        return (T) Enhancer.create(cls, this);    }    @Override    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {        log.info("ready to call getFont in FontProviderCGLibProxy, args is {}", args);        Object result = methodProxy.invokeSuper(o, args);        log.info("proxy method result is {}", result);        return result;    }}

抽象代理工厂

public interface ProviderFactory {    FontProvider getFontProviderStaticProxy();    FontProvider getFontProviderDynamicProxy();    FontProvider getFontProviderCGlibProxy();}

工厂方法实现

@Slf4jpublic class ProviderFactoryImpl implements ProviderFactory {    @Override    public FontProvider getFontProviderStaticProxy() {        log.info("Get FontProvider by Simple Proxy");        return new FontProviderSimpleProxy(new FontProviderImpl());    }    @Override    public FontProvider getFontProviderDynamicProxy() {        log.info("Get FontProvider by JDK Dynamic Proxy");        Class<FontProvider> targetClass = FontProvider.class;        return (FontProvider) Proxy.newProxyInstance(targetClass.getClassLoader(),                new Class[]{targetClass},                new FontProviderDynamicProxy(new FontProviderImpl()));    }    @Override    public FontProvider getFontProviderCGlibProxy() {        log.info("Get FontProvider by CGLib Proxy");        FontProviderCGLibProxy fontProviderCGLibProxy = new FontProviderCGLibProxy();        FontProvider fontProvider = fontProviderCGLibProxy.getProxy(FontProviderImpl.class);        return fontProvider;    }}

方法调用

@Slf4jpublic class ProxyEntry {    public static void main(String[] args) {        ProviderFactoryImpl providerFactoryImpl = new ProviderFactoryImpl();        FontProvider fontProviderStaticProxy = providerFactoryImpl.getFontProviderStaticProxy();        log.info("{}", fontProviderStaticProxy.getFont("Microsoft YaHei"));        log.info("***********************************************");        FontProvider fontProviderDynamicProxy = providerFactoryImpl.getFontProviderDynamicProxy();        log.info("{}", fontProviderDynamicProxy.getFont("微软雅黑"));        log.info("***********************************************");        FontProvider fontProviderCGlibProxy = providerFactoryImpl.getFontProviderCGlibProxy();        log.info("{}", fontProviderCGlibProxy.getFont("微软雅黑"));    }}

JDK 动态代理 vs CGLib Proxy

  • JDK动态代理只能通过接口来代理,因此,目标委托类需要实现一个接口,代理类也需要同时实现该接口。

  • CGLIB可以通过子类创建代理,在这种应用场景下,代理类成为目标类的子类,不需要接口。

这里写图片描述

EnableAspectJAutoProxy

Spring中添加@EnableAspectJAuotProxy注解用以支持@AspectJ自动代理

@EnableAspectJAutoProxy(proxyTargetClass=true)

强制Spring 容器使用CGLib代理,而非默认的基于接口的JDK动态代理方式。

https://stackoverflow.com/questions/10664182/what-is-the-difference-between-jdk-dynamic-proxy-and-cglib
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/EnableAspectJAutoProxy.html

原创粉丝点击