1. JDK代理和CGLIB代理

1)JDK动态代理是基于拦截器和反射实现的,不需要第三方库支持,只需要JDK环境即可。

  条件/实现步骤:

    必须实现InvocationHandler接口;

    使用Proxy.newProxyInstance产生代理对象;

       被代理的对象必须要实现接口;

    内部采用asm技术动态生成字节码。

演示示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyPattern {

    interface Foo {
        void foo();
    }

    static class Target implements Foo {
        @Override
        public void foo() {
            System.out.println("target foo exec method");
        }
    }

    /**
     * jdk代理只能针对接口进行代理
     * 内部采用asm技术动态生成字节码
     * @param args 命令参数
     */
    public static void main(String[] args) {
        Target target = new Target();
        ClassLoader classLoader = JdkProxyPattern.class.getClassLoader();
        Foo proxy = (Foo)Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before target proxy foo");
                Object result = method.invoke(target, args);

                System.out.println("after target proxy foo");
                return result;

            }
        });
        proxy.foo();
    }

}

  jdk动态代理的局限性在于只能对接口进行代理,不能对类进行代理。另外未被接口话的方法在代理类中将不可被代理。

2)CGLIB(Code Generation Library)动态代理. cglib是一个强大的高性能高质量的code生成类库,可以在运行期扩展Java类与实现Java接口。

  条件/实现步骤:比如类A为被代理类

    由于是采用的继承的方式,首先A不可以是final类;

    查找A上的所有非final的public类型的方法定义,将这些方法的定义转换成字节码;

    将组成的字节码转换成相应的代理的class对象;

    实现MethodInterceptor接口,用来处理代理类上所有方法的请求。

演示示例 (这里使用了spring框架内中的cglib)

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author cy.K
 * @since 
 */
public class CglibProxyPattern {

    public static void main(String[] args) {
        Business business = new Business();
        CgProxy cgProxy = new CgProxy();

        // cglib中加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        // 设置代理类
        enhancer.setSuperclass(business.getClass());
        // 设置回调
        enhancer.setCallback(cgProxy);
        Business proxy = (Business)enhancer.create();
        proxy.code();
    }

}

class Business {
    public void code(){
        System.out.println("business does");
    }
}

class CgProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before proxy business");
        methodProxy.invokeSuper(o, args);
        System.out.println("after proxy business");
        return null;
    }
}
View Code

 springAOP便是使用的CGLIB动态代理来实现的。

  优点:对比JDK代理,CGLIB可以对类进行代理;另一个是cglib的fastclass机制使得它比使用java反射实现代理来得要快。

  缺点:无法对final类、final方法进行代理;cglib代理对象性能高于jdk代理,但是创建代理的耗时比jdk代理多,故更适合单例对象。非单例对象,jdk代理创建对象更快。

SpringAOP同时使用JDK代理和CGLIB动态代理,如果不强制,springAOP默认使用JDK动态代理。 

当我们需要强制使用CGLIB来实现AOP的时候,需要xml中配置spring.aop.proxy-target-class=true或启动类中加上@EnableAspectJAutoProxy(proxyTargetClass = true)  

 

posted on 2023-03-15 17:14  crabKing  阅读(29)  评论(0)    收藏  举报