Java代理

代理模式:

代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象和一个委托类的对象关联,代理类的对象本身并不是真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。


按照代理的创建时期,代理类可以分为两种:

静态代理:创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了

动态代理:在程序运行时,运用反射机制动态创建而成。


公共接口:

package com.learns.proxy;

public interface Count {
	
	// 查看帐号方法
	public void queryCount();
	
	// 修改帐号方法
	public void updateCount();
	
}
接口实现类:

package com.learns.proxy;

public class CountImpl implements Count {

	public void queryCount()
	{
		System.out.println("查看账户方法");
	}
	
	public void updateCount()
	{
		System.out.println("修改账户方法");
	}
	
}

一、静态代理

package com.learns.proxy;

public class CountProxy implements Count {

	private CountImpl countImpl;
	
	public CountProxy(CountImpl countImpl)
	{
		this.countImpl = countImpl;
	}
	
	public void queryCount()
	{
		System.out.println("查询处理之前");
		countImpl.queryCount();
		System.out.println("查询处理之后");
	}
	
	public void updateCount()
	{
		System.out.println("修改处理之前");
		countImpl.updateCount();
		System.out.println("修改处理之后");
	}
	
}
测试类:

package com.learns.proxy;

public class TestCount {
	public static void main(String[] args) {
		CountImpl countImpl = new CountImpl();
		CountProxy countProxy = new CountProxy(countImpl);
		countProxy.updateCount();
		countProxy.queryCount();
	}
}
二、JDK动态代理

JDK动态代理使用到一个Proxy类和一个InvocationHandler接口。Proxy仅支持interface代理(也就是代理类必须实现接口)

InvocationHandler接口:
public interface InvocationHandler {
           public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例

package com.learns.proxy.jdk;

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

public class CountProxyFactory implements InvocationHandler {
	
	private Object target;
	
	public Object bind(Object target)
	{
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	
	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
	{
		boolean objFlag = method.getDeclaringClass().getName().equals("java.lang.Object");
		
		Object result = null;
		if(!objFlag)
		{
			System.out.println("代理before");
		}
		result = method.invoke(this.target, args);
		if(!objFlag)
		{
			System.out.println("代理after");
		}
		return result;
	}
}
测试类:

package com.learns.proxy.jdk;

import com.learns.proxy.Count;
import com.learns.proxy.CountImpl;

public class CountProxyTest {

	public static void main(String[] args)
	{
		// 下面使用JDK的代理类,一个代理可以代理很多接口
		Count count = (Count)new CountProxyFactory().bind(new CountImpl());
		System.out.println(count);
		count.queryCount();
	}
}
三、CGLIB动态代理

针对JDK仅支持实现接口的委托类进行代理的缺陷,CGLIB解决了这个问题。 使其委托类也可是非接口实现类。

CGLIB内部使用到ASM,所以需要引入asm-3.3.jar、cglib-2.2.2.jar

注意:cglib版本为3.0或3.1,asm版本为3.1时。版本冲突,报错java.lang.IncompatibleClassChangeError: class net.sf.cglib.core.DebuggingClassWriter has interface org.objectweb.asm.ClassVisitor as super class。使用cglib2.2可解决此问题,该版本中的DebuggingClassWriter的父类为ClassWriter


非接口实现类:

package com.learns.proxy.cglib;

public class Person {
	
	public void show()
	{
		System.out.println("showing");
	}
}
代理类:

package com.learns.proxy.cglib;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CountCglibProxyFactory implements MethodInterceptor {

	private Object target;
	
	public Object getInstance(Object target)
	{
		this.target = target;
		return Enhancer.create(this.target.getClass(), this);
	}
	
	public Object intercept(Object obj,Method method,Object[] args,MethodProxy methodProxy) throws Throwable
	{
		boolean objFlag = method.getDeclaringClass().getName().equals("java.lang.Object");
		if(!objFlag)
		{
			System.out.println("before");
		}
		Object result = null;
		result = methodProxy.invokeSuper(obj, args);
		if(!objFlag)
		{
			System.out.println("after");
		}
		return result;
	}
}
测试类:

package com.learns.proxy.cglib;

import com.learns.proxy.Count;
import com.learns.proxy.CountImpl;

public class CountCglibProxyTest {

	public static void main(String[] args) {
		Count count = (Count)new CountCglibProxyFactory().getInstance(new CountImpl());
		count.updateCount();
		
		Person person = (Person)new CountCglibProxyFactory().getInstance(new Person());
		System.out.println(person);
		person.show();
	}
}

参考文章:

http://blog.csdn.net/yuanlaishinizhu/article/details/12998847

http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值