设计模式java-04.代理模式
2018-03-01 19:51
597 查看
java的三种代理模式
代理模式提供了对目标对象的另外的访问方式,即通过代理对象访问目标对象。这样做的好处是尅在目标对象实现的基础上,增强额外的操作功能,即扩张目标对象的功能。
举个栗子来说明代理的作用:假如我们想买辆车,那么并不是直接找汽车生产厂家,而是找4S店(四儿子),来达到同样买车的目的。这里的车就是一个目标对象,厂家只要负责生产车,而其他的事情就交由厂家的代理4S店来完成。
一,静态代理
静态代理在使用时需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口或者是继承相同的父类。
下面还是以消费者买车为例子来解释:
汽车生产厂家要卖车,但是不是自己直接卖,而是交由4S店来卖:
这样我们定义一个卖车的接口
汽车生产厂家来实现这个接口,它要把车卖出去:
接下来4S店来代理卖汽车厂家生产的车了:
我们来测试下代码:
这样就是一个完整的静态代理的例子,通过FourShopSaleCar来间接完成卖车的动作,接下来我们看看4S店是怎么揩油加价的,为了方便我们引入一个Car对象;
4S店加价出售
然后就卖出去了
执行结果,多买了200块,多卖的这两百块就是代理模式的好处了,可以在卖车前和卖车后做做手脚,搞搞其他的事情,赚钻外快什么的。
这个就是静态代理了,下面我们了解下动态代理。静态代理的缺点就是需要实现目标对象接口方法,也就是这里的FourShopSaleCar.saleCar方法。
二,动态代理
动态代理一般分为使用jdk自带api来处理,和使用cglib来代理两种模式。
动态代理的特点就是不需要实现目标对象的接口方法,主要使用到了java.lang.reflect.Proxy类中的newProxyInstance方法。
这个方法有三个参数:
ClassLoader loader指定当前目标对象使用类加载器,获取加载器的方法是固定的
Class<> interfaces目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h 事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
让我们来创建一个代理工厂类:
测试一下我们的代理工厂类:
执行结果
这里我们已经不需要像静态代理中的FourShopSaleCar一样来实现IBaseSaleCar中的saleCar接口了。这个就是动态代理的优势了。
三、cglib动态代理
jdk动态代理只能针对实现了接口的类,一般没有实现接口的类不能代理。cglib就是针对类来实现代理的,它的原理是针对指定目标类生成一个子类,并覆盖其方法增强其实现。因为采用的是继承,因此不能针对final修饰的类进行代理。使用cglib进行动态代理,完全不受代理类必须实现接口的限制,而且cglib底层使用ASM字节码生成框架,使用字节码技术生成代理类,比java反射的效率要高。
下面来看个例子:
使用cglib动态代理我们需要引入2个包:cglib.jar,asm.jar
定义了一个拦截器,在调用目标方法之前,cglib回调MethodInterceptor接口方法拦截,来实现自己的业务逻辑,类似
于JDK中的InvocationHandler接口。
参考:https://www.cnblogs.com/cenyu/p/6289209.html
代理模式提供了对目标对象的另外的访问方式,即通过代理对象访问目标对象。这样做的好处是尅在目标对象实现的基础上,增强额外的操作功能,即扩张目标对象的功能。
举个栗子来说明代理的作用:假如我们想买辆车,那么并不是直接找汽车生产厂家,而是找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()); } }
参考:https://www.cnblogs.com/cenyu/p/6289209.html
相关文章推荐
- JAVA设计模式(09):结构型-代理模式(Proxy)
- JAVA设计模式实战---代理模式!!!
- Java设计模式Proxy之动态代理
- java设计模式(4)--代理模式
- java设计模式-代理模式
- 代理模式【设计模式学习-04】
- java设计模式之代理模式
- 通俗系列-Java设计模式-代理模式
- java 设计模式-代理
- (二)Java设计模式--代理模式
- java设计模式-代理模式
- 深入浅出――基于Java的代理设计模式
- Java设计模式学习---代理模式
- Java设计模式-代理模式
- JAVA设计模式--代理模式(动态)(一)
- 设计模式-java实现代理模式(静态代理)
- 代理设计模式之(静态代理+Java自身提供的动态代理机制)
- Java设计模式—Proxy动态代理模式
- java设计模式——代理模式
- 使用自动生成java文件和自动编译的动态代理模式-马士兵设计模式教程