Java Proxy And CGLIB Proxy

代理:能在目标方法执行前后或异常时做一些处理,并且可以多层代理,形成代理链

 

手动编码实现

interface Dao {
    void save();
}
class DaoImpl implements Dao {
    @Override
    public void save() {
        System.out.println("save...");
    }
}
class DaoProxy implements Dao{
    private Dao target;

    public DaoProxy(Dao target) {
        this.target = target;
    }

    @Override
    public void save() {
        System.out.println("before...");
        target.save();
        System.out.println("after...");
    }
}

public class StaticProxyTest {
    public static void main(String[] args) {
        DaoImpl target = new DaoImpl();
        Dao userDao = new DaoProxy(target);
        userDao.save();
    }
}

 

JDK 动态代理(代理接口)

interface Dao {
    void save();
}
class DaoImpl implements Dao {
    @Override
    public void save() {
        System.out.println("save...");
    }
}
public class DynamicProxyTest {
    public static void main(String[] args) {
        Object target = new DaoImpl();
        /**
         * loader:业务对象的类加载器
         * interfaces:业务对象实现的所有的接口,可直接指定业务类实现的接口 Class[]
         * h:InvocationHandler 对象,最终由它调用业务对象的方法
         * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
         */
        Dao dao = (Dao) Proxy.newProxyInstance(DaoImpl.class.getClassLoader(), new Class<?>[]{Dao.class}, new InvocationHandler() {
            /**
             * @param proxy 代理对象
             * @param method 代理的方法对象
             * @param args 方法调用时参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                if (method.getName().equals("save")) {
                    System.out.println("before...");
                    result = method.invoke(target, args);
                    System.out.println("after...");
                }
                return result;
            }
        });
        dao.save();
    }
}

 

CGLIB(Code Generator Library)动态代理(代理类)

public class Dao {
    public void select() {
        System.out.println("select()");
    }
}
public class DaoProxy implements MethodInterceptor {
    /**
     * @param object 要进行增强的对象
     * @param method 拦截的方法
     * @param objects 参数列表,基本数据类型需要传入其包装类型
     * @param proxy 对方法的代理,invokeSuper 方法表示对被代理对象方法的调用
     */
    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
        System.out.println("Before Method Invoke");
        proxy.invokeSuper(object, objects);
        System.out.println("After Method Invoke");

        return object;
    }
}
public static void main(String[] args) {
    DaoProxy daoProxy = new DaoProxy();

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Dao.class);
    enhancer.setCallback(daoProxy);

    Dao dao = (Dao) enhancer.create();
    dao.select();
}

 

静态代理

静态代理是编译阶段生成 AOP 代理类,也就是说生成的字节码就织入了增强后的 AOP 对象,并不会创建出多余的对象

实现方式:

  • 包装器模式:持有目标对象的引用,然后实际上是调用目标对象的方法。 这种方式也可称为代理模式,但是有明显的缺点(比如一般都需要实现同一个接口,且它是以编码的方式去实现的,侵入性高)
  • AspectJ 静态代理方式:非常非常强大。AspectJ 并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到 class 文件。由于是静态织入的,所以性能相对来说比较好。AspectJ 不受类的特殊限制,不管方法是 private、static 或 final 的,都可以代理,AspectJ 不会代理除了限定方法之外任何其他诸如 toString(),clone() 等方法,唯一缺点就是必须有 AspectJ 自己的编译器的支持,所以其实很少使用,Spring 也是提供了相关类支持,比如:LoadTimeWeaverAwareProcessor,基于 AspectJ 的静态代理方式非常强大,但是它依赖于它自己的编译器。并且还有自己的个性化语言,使用起来不够方便,因此其实还是使用得较少的。主要还是以动态代理为主

动态代理

动态代理不会修改字节码,而是在内存中临时生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法

这在平时使用中得到了大量的应用,因为使用简单并且还非常灵活。

 


https://blog.csdn.net/f641385712/article/details/89362021

https://blog.csdn.net/f641385712/article/details/88952482

https://blog.csdn.net/f641385712/article/details/83539891

https://www.cnblogs.com/jhxxb/p/10557738.html

posted @ 2019-03-14 20:01  江湖小小白  阅读(320)  评论(0编辑  收藏  举报