• Spring专题1: 静态代理和动态代理


    为什么需要代理模式?

    代理对象处于访问者和被访问者之间,可以隔离这两者之间的直接交互,访问者与代理对象打交道就好像在跟被访者者打交道一样,因为代理者通常几乎会拥有全部被代理者的职能,代理对象能够处理的访问请求就不必要劳烦被访问者来处理了.

    • 代理对象可以减少被访问者的负担,
    • 在转发访问请求之前或者之后加入特定的逻辑.比如安全限制,或者做一些中间操作
    • 便于通过配置, 直接修改实际的实现类
    • 便于测试

    讲讲静态代理模式的优点及其瓶颈?

    直接编写实现方法的代理类, 这种代理方式称为静态代理, 这也是效率最高的一种方式, 因为所有的类都是已经编写完成的, 客户端只需要取得代理对象并且执行即可.
    静态代理虽然效率较高, 但其缺点在于要为每个接口实现一个代理类, 而这些代理类中的代码几乎是一致的, 这在大型系统中将会产生很大的维护问题.


    对Java 接口代理模式的实现原理的理解?

    使用 Proxy 和 InvocationHandler 来实现
    对于接口A, 以及其实现类AImpl,
    创建一个子类 MyInvocationHandler, 继承自 InvocationHandler , 其构造参数可以用 AImpl, 也可以不用
    Proxy.newProxyInstance() , 输入指定的接口和MyInvocationHandler实例, 创建其代理对象, 然后就可以用A接口方法进行调用, 调用时都会经过 MyInvocationHandler.invoke() 方法


    如何使用 Java 反射实现动态代理?

    如果使用java反射, 则可以使用这样的形式得到代理类

    public class MyInvocationHandler implements InvocationHandler {
    	// 目标对象(需要被代理的对象)
    	private Object target;
    
     	public void setTarget(Object target) {
    		this.target = target;
    	}
     	/**
    	 * 执行代理对象的所有方法时都会被替换成执行如下的invoke方法
    	 */
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		// 实例化一个增强类
    		Extend extend = new Extend();
    		// 执行增强方法1(模拟spring前置增强)
    		extend.ExtendMethod1();
    		Object result = method.invoke(target, args);// 【执行目标方法】
    		// 执行增强方法2(模拟spring后置增强)
    		extend.ExtendMethod2();
    		return result;
    	}
    }
    
    public class MyProxyFactory {
    	/*
    	 * 获取一个目标对象(目标类必须实现接口)的代理对象
    	 */
    	public static Object getProxy(Object target) {
    		// 实例化一个InvocationHandler类, 并传入目标对象
    		MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
    		myInvocationHandler.setTarget(target);
    		// 生成代理对象
    		Object proxyObject = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInvocationHandler);
    		return proxyObject;
    	}
    }
    

    Java 接口代理模式的指定增强?

    在 InvocationHandler.invoke() 中, 在执行对象方法的前后, 进行额外的操作


    谈谈对Cglib 类增强动态代理的实现?

    https://blog.csdn.net/yaomingyang/article/details/82762697

    CGLIB是一个强大、高性能的字节码生成库, 它用于在运行时扩展Java类和实现接口;本质上它是通过动态的生成一个子类去覆盖所要代理的类(非final修饰的类和方法).
    Enhancer是一个非常重要的类, 它允许为非接口类型创建一个JAVA代理, Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法, 和JDK动态代理不一样的是不管是接口还是类它都能正常工作.

    • net.sf.cglib.proxy.Callback接口, 在cglib包中是一个很关键的接口, 所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口
    • net.sf.cglib.proxy.MethodInterceptor接口, 是通用的回调(callback)类型, 他经常被AOP用来实现拦截(intercept)方法的调用

    一个常见的通过 MethodInterceptor 和 Enhancer 实现的代理实现方式

    public class ProxyFactory implements MethodInterceptor {
    	private Object obj; //要代理的真实对象
    
    	public Object createProxy(Object target) {
    		this.obj = target;
    		Enhancer enhancer = new Enhancer();
    		enhancer.setSuperclass(this.obj.getClass()); //设置代理目标
    		enhancer.setCallback(this); //设置单一回调对象, 在调用中拦截对目标方法的调用
    		enhancer.setClassLoader(this.obj.getClass().getClassLoader()); //设置类加载器
    		return enhancer.create();
    	}
    
    	/**
    	 * 方法描述 当对基于代理的方法回调时, 在调用原方法之前会调用该方法
    	 * 拦截对目标方法的调用
    	 */
    	@Override
    	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    		Object result = null;
    		try {
    			before(); //前置通知
    			result = proxy.invokeSuper(obj, args);
    			after(); //后置通知
    		} catch (Exception e) {
    			exception(); //异常通知
    		} finally {
    			beforeReturning(); //方法返回前通知
    		}
    		return result;
    	}
    
    	private void before() {
    		System.out.println("before method invoke...");
    	}
    	private void after() {
    		System.out.println("after method invoke...");
    	}
    	private void exception() {
    		System.out.println("exception method invoke...");
    	}
    	private void beforeReturning() {
    		System.out.println("beforeReturning method invoke...");
    	}
    }
    

    讲解JDK 动态代理和 CGLIB 代理原理以及区别?

    cglib生成的代理实际上是子类, 可以不需要接口.

  • 相关阅读:
    MFC 简介
    C++使用thread类多线程编程
    C++中stack
    C++中头文件简介(stdio.h & chrono)
    别人写的很好Arduino教材
    Communicating to 2 SPI Slaves with USART & SPI ports on Atmega16U2
    HDU 2089 不要62(挖个坑=-=)
    HDU 3555 Bomb(数位DP)
    HDU 3480 Division(斜率优化+二维DP)
    HDU 3045 Picnic Cows(斜率优化DP)
  • 原文地址:https://www.cnblogs.com/milton/p/15808130.html
Copyright © 2020-2023  润新知