美文网首页
Spring系列之AOP(1)—— JDK动态代理和CigLib

Spring系列之AOP(1)—— JDK动态代理和CigLib

作者: 康康不遛猫 | 来源:发表于2017-05-08 11:23 被阅读0次

1、JDK动态代理

JDK动态代理通过JDK的Proxy类实现,JDK提供的动态代理需要实现InvocationHandler接口的invoke方法.此方法为整个代理的入口。方法签名为

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

第一个参数是代理对象,第二个参数是目标方法,第三个参数是目标方法参数

public class ProxyHandler implements InvocationHandler{
    Object target;
    public ProxyHandler(Object target) {
        this.target=target;
    }
    public void before(String param) throws Throwable{
        if(!param.equals("magicalwolf"))
            throw new IllegalArgumentException();
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        before((String)args[0]);
        return method.invoke(target, args);
    }
}

之后通过Proxy类的newProxyInstance方法创建代理对象

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

第一个参数是目标对象的类加载器,第二个参数是目标类实现的接口,第三个参数是处理器InvocationHandler

public class Main {
    public static void main(String[] args) {
        Subject target=new RealSubject();
        Subject proxy=(Subject)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new ProxyHandler(target));
        proxy.request("magicalwolf");
        proxy.request("hello");
    }
}

可以看到使用JDK提供的动态代理无需为每个对象都实现一个代理类,通过处理器,可以对不同的对象生成代理类。
newProxyInstance方法通过接口生成子类,然后通过反射构建实例

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

注:但是JDK的动态代理是通过代理接口实现的,如果对象没有实现接口,那就无能为力了。

Ciglib动态代理

CGLIB是一个强大的高性能的代码生成包,在运行时动态生成字节码并生成新类。
CGLIB提供了MethodInterceptor接口,当调用目标方法时被回调,类似于InvocationHandler.

public class RequestInterceptor implements MethodInterceptor{

    public void before(String param) throws Throwable{
        if(!param.equals("magicalwolf"))
            throw new IllegalArgumentException();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        before((String)args[0]);
        return proxy.invokeSuper(obj, args);//调用父类的方法
    }
}

生成代理类

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer(); //字节码增强器
        enhancer.setSuperclass(RealSubject.class);  //代理类
        enhancer.setCallback(new RequestInterceptor());//回掉方法  
        Subject proxy=(Subject) enhancer.create();
        proxy.request("magicalwolf");
        proxy.request("hello");
    }
}

可以看到,CGLIB是通过动态生成目标类的子类,在子类中设置拦截逻辑,来进行动态代理。因此目标类的方法不能被final修饰。

总结

jdk动态代理通过JDK的proxy类实现,要求被代理类必须提供接口,原理是通过反射机制,生成接口新的实现类。
cglib动态代理通过cglib字节码增强器实现,原理是生成被代理类的子类,因此方法不能用final修饰。

相关文章

  • Spring系列之AOP(1)—— JDK动态代理和CigLib

    1、JDK动态代理 JDK动态代理通过JDK的Proxy类实现,JDK提供的动态代理需要实现InvocationH...

  • Spring之使用XML配置Spring AOP

    1.aop的原理 Spring AOP底层主要使用了JDK动态代理和cglib动态代理。具体可看文章设计模式之代理...

  • java动态代理

    目录: 简介 jdk动态代理 cglib动态代理 jdk动态代理与cglib的区别 应用spring的aop 简介...

  • JDK动态代理和CGLIB动态代理的区别

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: JDK动态代理只提供接口的代...

  • Spring AOP

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被...

  • Spring AOP DefaultAdvisorAutoPro

    Spring AOP源码目录 Spring AOP源码01:Jdk动态代理底层源码Spring AOP源码02:P...

  • 2018-09-16

    AOP的XML配置: AOP的先关术语: Spring底层的AOP实现原理 动态代理: JDK动态代理:只能对实现...

  • Spring AOP中的动态代理

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: (3)静态代理与动态代理区别...

  • SpringAOP源码解析过程

    spring的AOP基于JDK的动态代理和cglib实现,默认代理对象是某个接口的实现就会使用JDK动态代理,否则...

  • 从零开始写Spring AOP框架-(链式代理)

    Spring AOP的核心是Cglib和JDK的动态代理,那我们先写Spring AOP的前置增强和后置增强 示例...

网友评论

      本文标题:Spring系列之AOP(1)—— JDK动态代理和CigLib

      本文链接:https://www.haomeiwen.com/subject/hexytxtx.html