目录

  • 一、静态代理
  • 二、动态代理

一、静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

代理接口:

/**
 * 代理接口
 */
public interface Rent {
	public void rent();
}

委托类,具体处理业务:

/**
 * 房东要出租房子
 */
public class Host implements Rent {
	@Override
	public void rent() {
		System.out.println("房东出租房子!");
	}
}

静态代理类 :

/**
 * 房子中介:代理
 */
public class Proxyhome implements Rent{

	private Host host;

	public Proxyhome(Host host) {
		this.host = host;
	}

	@Override
	public void rent() {
		seeHouse();
		host.rent();
		fare();
	}

	// 看房
	public void seeHouse(){
		System.out.println("中介带你看房子!");
	}

	// 收中介费
	public void fare(){
		System.out.println("中介收中介费!");
	}
}

客户类 :

public class Client {

	public static void main(String[] args) {
		Host host = new Host();
		//代理房东买房子
		Proxyhome proxy = new Proxyhome(host);
		proxy.rent();
	}
}

静态代理的优缺点:

优点:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务。
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍一开发效率会变低

二、动态代理

动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

PS反射可以通过类的类加载器直接获得类的任何信息(许多框架都是建立在反射上的,如Spring系列),也可以参考注解和反射 体验反射的强大功能。

再者动态代理有点类似Spring中AOP(横向切入),在不改变原有的代码上加入需要的业务。

动态代理和静态代理角色一样。动态代理的代理类是动态生成的,不是我们直接写的!

动态代理分为两大类:基于接口的动态代理,基于类的动态代理

  • 基于接口:JDK动态代理**【我们在这里使用】**
  • 基于类:cglibo
  • ava字节码实现:javasist
    动态代理的实现类:
/**
 * 动态代理卖房子业务
 */
public class ProxyInvocationHandler implements InvocationHandler {

	// 被代理的接口
	private Rent rent;

	public void setRent(Rent rent){
		this.rent=rent;
	}

	//生成得到代理类
	public Object getProxy(){
		return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
	}

	//处理代理的实例,并返回结果
  // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象  
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//动态代理的本质,就是使用反射机制实现的!
		Object result = method.invoke(rent, args);
		return result;
	}
}

客户类:

public class Client2 {
	public static void main(String[] args) {
		Host host = new Host();
		//代理房东买房子
		ProxyInvocationHandler pih = new ProxyInvocationHandler();
		pih.setRent(host);
		Rent proxy = (Rent) pih.getProxy();
		proxy.rent();
	}
}

动态代理的好处:

  1. 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  2. 公共也就就交给代理角色!实现了业务的分工!
  3. 公共业务发生扩展的时候,方便集中管理!
  4. 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  5. 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
    基于接口的动态代理的代码差不多是固定的,我们可以把固定的代码做成一个工具类。下面给出:
/**
 * 代理工具类
 */
public class ProxyObjectInvocationHandler implements InvocationHandler {

	// 被代理的接口
	private Object target;

	public void setTarget(Rent rent){
		this.target=rent;
	}

	//生成得到代理类
	public Object getProxy(){
		return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
	}

	//处理代理的实例,并返回结果
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		log(method.getName());
		//动态代理的本质,就是使用反射机制实现的!
		Object result = method.invoke(target, args);
		return result;
	}

  //这里自己可以拓展自己需要的业务
	public void log(String msg){
		System.out.println("执行了" + msg + "的方法");
	}
}