java的三种代理模式
代理模式提供了对目标对象的另外的访问方式,即通过代理对象访问目标对象。这样做的好处是尅在目标对象实现的基础上,增强额外的操作功能,即扩张目标对象的功能。
举个栗子来说明代理的作用:假如我们想买辆车,那么并不是直接找汽车生产厂家,而是找4S店(四儿子),来达到同样买车的目的。这里的车就是一个目标对象,厂家只要负责生产车,而其他的事情就交由厂家的代理4S店来完成。
一,静态代理
静态代理在使用时需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口或者是继承相同的父类。
下面还是以消费者买车为例子来解释:
汽车生产厂家要卖车,但是不是自己直接卖,而是交由4S店来卖:
这样我们定义一个卖车的接口
public interface IBaseSaleCar{
void saleCar();
}
汽车生产厂家来实现这个接口,它要把车卖出去:
public class CarFactorySale implements IBaseSaleCar{
@Override
public void saleCar(){
System.out.println("卖我(汽车厂家)生产的车");
}
}
接下来4S店来代理卖汽车厂家生产的车了:
public class FourShopSaleCar implements IBaseSaleCar{
private IBaseSaleCar target;
public FourShopSaleCar(IBaseSaleCar target){
this.target = target;
}
@Override
public void saleCar(){
target.saleCar();
}
}
我们来测试下代码:
public class TestProxy{
public static void main(String[] args){
CarFactorySale target = new CarFactorySale();
FourShopSaleCar proxy = new FourShopSaleCar(target);
proxy.saleCar();
}
}
这样就是一个完整的静态代理的例子,通过FourShopSaleCar来间接完成卖车的动作,接下来我们看看4S店是怎么揩油加价的,为了方便我们引入一个Car对象;
public class Car {
/**品牌 */
private String brand;
/** 价格 */
private Long price;
public Car(String brand, Long price){
this.brand = brand;
this.price = price;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String toString(){
return "我卖"+this.brand+"牌子的车,我卖"+this.price+"块钱";
}
}
public interface IBaseSaleCar {
void saleCar(Car car);
}
public class CarFactorySale implements IBaseSaleCar{
@Override
public void saleCar(Car car){
System.out.println(car.toString());
}
}
4S店加价出售
public class FourShopSaleCar implements IBaseSaleCar{
private IBaseSaleCar target;
public FourShopSaleCar(IBaseSaleCar target){
this.target = target;
}
@Override
public void saleCar(Car car){
//加了200块
car.setPrice(car.getPrice() + 200L);
target.saleCar(car);
}
}
然后就卖出去了
public class TestProxy{
public static void main(String[] args){
//厂家定价1000块
Car car = new Car("Benz", 1000L);
CarFactorySale target = new CarFactorySale();
FourShopSaleCar proxy = new FourShopSaleCar(target);
//4S店卖的时候偷偷加了200块
proxy.saleCar(car);
}
}
执行结果,多买了200块,多卖的这两百块就是代理模式的好处了,可以在卖车前和卖车后做做手脚,搞搞其他的事情,赚钻外快什么的。
我卖Benz牌子的车,我卖1200块钱
这个就是静态代理了,下面我们了解下动态代理。静态代理的缺点就是需要实现目标对象接口方法,也就是这里的FourShopSaleCar.saleCar方法。
二,动态代理
动态代理一般分为使用jdk自带api来处理,和使用cglib来代理两种模式。
动态代理的特点就是不需要实现目标对象的接口方法,主要使用到了java.lang.reflect.Proxy类中的newProxyInstance方法。
这个方法有三个参数:
ClassLoader loader指定当前目标对象使用类加载器,获取加载器的方法是固定的
Class<> interfaces目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h 事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
让我们来创建一个代理工厂类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
//要代理的对象
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
public Object getProxyFactoryInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
Object returnValue = method.invoke(target, args);
return returnValue;
}
});
}
}
测试一下我们的代理工厂类:
public class ProxyTest {
public static void main(String[] args){
Car car = new Car("BMW", 1000L);
IBaseSaleCar target = new CarFactorySale();
System.out.println(target.getClass());
IBaseSaleCar proxy = (IBaseSaleCar) new ProxyFactory(target).getProxyFactoryInstance();
System.out.println(proxy.getClass());
proxy.saleCar(car);
}
}
执行结果
class com.test.CarFactorySale
class com.sun.proxy.$Proxy0
我卖BMW牌子的车,我卖1000块钱
这里我们已经不需要像静态代理中的FourShopSaleCar一样来实现IBaseSaleCar中的saleCar接口了。这个就是动态代理的优势了。
三、cglib动态代理
jdk动态代理只能针对实现了接口的类,一般没有实现接口的类不能代理。cglib就是针对类来实现代理的,它的原理是针对指定目标类生成一个子类,并覆盖其方法增强其实现。因为采用的是继承,因此不能针对final修饰的类进行代理。使用cglib进行动态代理,完全不受代理类必须实现接口的限制,而且cglib底层使用ASM字节码生成框架,使用字节码技术生成代理类,比java反射的效率要高。
下面来看个例子:
使用cglib动态代理我们需要引入2个包:cglib.jar,asm.jar
定义了一个拦截器,在调用目标方法之前,cglib回调MethodInterceptor接口方法拦截,来实现自己的业务逻辑,类似
于JDK中的InvocationHandler接口。
public class UserDaoImpl {
public void save() {
System.out.println("Mysql执行保存...");
}
}
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 CglibProxyFactory {
private Object obj;
public CglibProxyFactory(Object obj) {
super();
this.obj = obj;
}
public Object getProxyFactory(){
//Enhancer类是cglib中的一个字节码增强器,它可以方便的为你所要处理的类进行扩展
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());//将目标对象所在的类作为Enhaner类的父类
enhancer.setCallback(new MethodInterceptor() {
//通过实现MethodInterceptor实现方法回调
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("事务开启...");
method.invoke(obj, args);
System.out.println("事务结束...");
return proxy;
}
});
return enhancer.create();//生成目标对象并返回
}
}
public class TestCglibProxy {
public static void main(String[] args){
UserDaoImpl userDao = new UserDaoImpl();
UserDaoImpl userDaoProxy = (UserDaoImpl) new CglibProxyFactory(userDao).getProxyFactory();
userDaoProxy.save();
System.out.println("目标对象类型:"+userDao.getClass());
System.out.println("代理对象类型:"+userDaoProxy.getClass());
}
}