java代理模式

代理模式(Proxy Pattern)的定义:为另一个对象提供一个替身或占位符,以控制对这个对象的访问(Head First设计模式给出的定义)。简单说即是在不改变源码的情况下,实现对目标对象的功能扩展。
Java的代理模式一共有三种 静态代理 jdk代理和cglib代理,后两种都属于动态代理。

1.静态代理
静态代理通过目标类与代理类实现同一个接口,代理类中实例化一个目标类的对象来实现。
代码:

//以下代码实现的功能是将目标类中的doFirst()方法返回的值变为大写


//这是目标类和代理类实现的接口
package service;
public interface IService {
	public String doFirst();
	public void doSecond();
}


//这是目标类
package service;
public class ServiceImpl implements IService {
	@Override
	public String doFirst() {
		System.out.println("执行doFirst()");
		String result="abcde";
		return result;
	}
	@Override
	public void doSecond() {
		// TODO 自动生成的方法存根
		System.out.println("执行doSecond()");
	}
}


//这是代理类
package service;
public class ServiceProxyImpl implements IService {
	IService service;
	public ServiceProxyImpl() {
		service =new ServiceImpl();
	}
	@Override
	public String doFirst() {
		//使目标类中doFirst()返回的字符串变为大写
		String result = service.doFirst();
		result=result.toUpperCase();
		return result;
	}
	@Override
	public void doSecond() {
		// TODO 自动生成的方法存根
		service.doSecond();
	}
}



//这是测试类
package main;
import service.IService;
import service.ServiceProxyImpl;
public class Test {
	public static void main(String[] args) {
		IService service=new ServiceProxyImpl();
		String result=service.doFirst();
		System.out.println(result);
		service.doSecond();
	}
}


静态代理在使用时,实例化的时代理类,而不是目标类。

缺点:这种实现方式很直观也很简单,但其缺点是代理对象必须提前写出,如果接口层发生了变化,代理对象的代码也要进行维护。如果能在运行时动态地写出代理对象,不但减少了一大批代理类的代码,也少了不断维护的烦恼,不过运行时的效率必定受到影响。这种方式就是接下来的动态代理。

2.jdk动态代理
jdk动态代理与静态代理的底层原理相同。jdk动态代理通过Proxy实现
Proxy通过静态方法newProxyInstance()返回代理类对象
newProxyInstance()方法有三个参数

  • ClassLoader loader:指定当前目标对象使用类加载器,写法固定
  • Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
  • InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类

代码:


//这是目标类和代理类实现的接口
package service;
public interface IService {
	public String doFirst();
	public void doSecond();
}


//这是目标类
package service;
public class ServiceImpl implements IService {
	@Override
	public String doFirst() {
		System.out.println("执行doFirst()");
		String result="abcde";
		return result;
	}
	@Override
	public void doSecond() {
		// TODO 自动生成的方法存根
		System.out.println("执行doSecond()");
	}
}


//这个是测试类  使用代理时时用Proxy的newProxyInstance方法动态创建的代理类
package main;

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

import service.IService;
import service.ServiceImpl;

public class Test {
	public static void main(String[] args) {
		//首先实例化一个目标类的对象
		final IService target=new ServiceImpl();
		
		//通过Proxy的newProxyInstance方法获取一个代理类对象
		IService service=(IService) Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(),
				new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						Object result = method.invoke(target, args);
						if(result!=null) {
							result=((String)result).toUpperCase();
						}
						return result;
					}
				});
		String result=service.doFirst();
		System.out.println(result);
		service.doSecond();
	}

}

缺点:可以看出静态代理和JDK代理有一个共同的缺点,就是目标对象必须实现一个或多个接口,假如没有,则可以使用Cglib代理,当然Cglib代理也可以用于目标对象有接口的情况。

3.Cglib代理
使用Cglib的前提条件:

  • 需要引入cglib的jar文件,由于Spring的核心包中已经包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
  • 目标类不能为final
  • 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

代码:

//这是目标类
package service;
public class Service {
	public String doFirst() {
		System.out.println("执行doFirst()");
		String result="abcde";
		return result;
	}
	public void doSecond() {
		System.out.println("执行doSecond()");
	}
}


//使用Cglib创建代理类  
package factory;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import service.Service;

public class ServiceProxyFactory implements MethodInterceptor {
	
	Service target;
	
	public ServiceProxyFactory() {
		target=new Service();
	}

	public Service serviceProxy() {
		//创建增强器对象
		Enhancer enhancer=new Enhancer();
		//指定目标类  即父类
		enhancer.setSuperclass(Service.class);
		//设置回调接口对象
		enhancer.setCallback(this);
		return (Service) enhancer.create();
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		Object result=method.invoke(target, args);
		if(result!=null) {
			result=((String)result).toUpperCase();
		}
		return result;
	}
}



//测试类
package main;

import factory.ServiceProxyFactory;
import service.Service;

public class Test {

	public static void main(String[] args) {
		Service s=new ServiceProxyFactory().serviceProxy();
		String result =s.doFirst();
		System.out.println(result);
		s.doSecond();
	}

}


在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值