Java中的代理模式

代理模式

  在代理模式里面,使用代理类控制对目标类的访问,通过代理对象控制对原对象的访问。这里的代理对象其实就是相当于是生活中的中介。

  举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。

  代理对象的存在隔离了用户和目标对象,并且可以通过给代理对象添加额外的功能来扩展目标类的功能,并且不用修改目标类的代码。总而言之,代理对象解决了直接访问对象而带来的问题。比如,要访问的对象在远程机器上面。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

  用户只会访问代理对象,代理对象是目标对象的扩展,代理对象会调用目标对象,用户不会直接访问目标对象。

静态代理

  静态代理是由程序员或是特定工具生成源代码,再对其进行编译,在程序员运行之前代理类的.class文件就已经被创建了。

BuyHouse接口:

public interface BuyHouse {
	void buyHouse();
}

BuyHouse接口实现:

public class BuyHouseImpl implements BuyHouse{
	@Override
	public void buyHouse() {
		System.out.println("I want to buy a house!");
	}
}

代理对象的实现:

public class BuyHouseProxy implements BuyHouse{
	private BuyHouse buyHouse;
	
	public BuyHouseProxy(BuyHouse buyHouse) {
		this.buyHouse=buyHouse;
	}
	@Override
	public void buyHouse() {
		System.out.println("before buy house");
		buyHouse.buyHouse();	
		System.out.println("after buy house");
	}

}

 测试类实现:

public class ProxyTest {
    public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        buyHouse.buyHosue();
        BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
        buyHouseProxy.buyHosue();
    }
}

JDK动态代理

  动态代理的代理对象是是在程序运行时通过java的反射机制生成的。在动态代理里面,我们并不需要为每一个服务都创建代理类,我们只需要实现一个代理处理器,真正的对象由JDK动态的为我们创建。

  动态处理器:

public class DynamicProxyHandler implements InvocationHandler{
	private Object object;
	
	public DynamicProxyHandler(Object object) {
		// TODO Auto-generated constructor stub
		this.object=object;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("before method");
		Object res=method.invoke(object, args);
		System.out.println("after method");
		return res;
	}

}

  测试代码:

public class DynamicProxyTest {
	public static void main(String[] args) {
		BuyHouse buyHouse=new BuyHouseImpl();
		BuyHouse proxyBuyHouse=(BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), 
				new Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse));
		proxyBuyHouse.buyHouse();
	}
}

  也可以直接将动态处理器写在Proxy.newProxyInstance方法中,这样代码比较简洁。

public class DynamicProxyTest {
	public static void main(String[] args) {
		final BuyHouse buyHouse=new BuyHouseImpl();
		BuyHouse proxyBuyHouse=(BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), 
				new Class[]{BuyHouse.class},
				new InvocationHandler(){@Override
				public Object invoke(Object proxy, Method method,
						Object[] args) throws Throwable {
					// TODO Auto-generated method stub
					System.out.println("before buy house");
					Object resObject=method.invoke(buyHouse, args);
					System.out.println("after buy house");
					return resObject;
				}});
		proxyBuyHouse.buyHouse();
	}
}

  JDK实现代理,只需要实现newProxyInstance方法,该方法需要接受三个参数。

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

  loader:目标类的类加载器。

  interfaces:目标类实现的接口集合,可以是一个,可以是多个。

  invocationHandler:动态处理器,当调用目标类方法时会调用动态处理器的invoke方法,这时invoke(Object proxy, Method method,Object[] args)的参数proxy是代理类,method是调用的代理类对象方法,args则是方法的参数。

  JDK动态代理的目标类一定要实现接口,否则不能用JDK的动态代理。

CGlib动态代理

创建CGlib代理类:

public class CglibProxy implements MethodInterceptor {
    private Object target;
    public Object getInstance(final Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("买房前准备");
        Object result = methodProxy.invoke(object, args);
        System.out.println("买房后装修");
        return result;
    }
}

 创建测试类:

public class CglibProxyTest {
    public static void main(String[] args){
        BuyHouse buyHouse = new BuyHouseImpl();
        CglibProxy cglibProxy = new CglibProxy();
        BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse);
        buyHouseCglibProxy.buyHosue();
    }
}

  这里CGLib和JDK动态代理实现代理模式的方法不同,JDK动态代理实现是通过代理类和目标类实现相同的接口实现的,而CGLib是通过让代理类继承目标类来实现的。

  CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

posted @ 2019-04-27 18:08  小白兔云  阅读(170)  评论(0编辑  收藏  举报