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

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() {
                    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动态代理)