代理模式
代理模式(Proxy Pattern)一个类代表另一个类的功能,通过代理对象访问目标对象,可以在目标对象实现的基础上,增强额外的功能。
代理模式解决的问题
在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
代理模式模式角色
抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
使用场景
代理对象访问,对真实访问对象的功能进行增加,在方法执行之前和执行之后,增加一些额外的逻辑。比如在处理业务之前记录日志,在执行业务之前开启事务,执行业务之后,提交事务,让开发人员更关注业务逻辑。
代码实现(3种实现方法)
1.静态代理
/** * 抽象类 */public interface Sourceable { void method();}
/** * 真实具体类 */public class Source implements Sourceable{ public void method() { System.out.println("target method"); }}
/** * 静态代理类 */public class StaticProxy implements Sourceable{ private Sourceable sourceable; public StaticProxy(Sourceable sourceable) { this.sourceable = sourceable; } public void method() { before(); sourceable.method(); after(); } public void before(){ System.out.println("关注java程序员思维"); } public void after(){ System.out.println("阅读文章"); }}
/** * 测试类 */public class Test { public static void main(String[] args) { Sourceable sourceable = new Source(); Sourceable proxy = new StaticProxy(sourceable); proxy.method(); }}
运行结果:
2.jdk版动态代理
1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理
/** * jdk版动态代理实现 */public class JdkDynamicProxy { //维护一个目标对象 private Object target; public JdkDynamicProxy(Object target){ this.target=target; } //给目标对象生成代理对象 public Object getProxyInstance(){ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); //执行目标对象方法 Object returnValue = method.invoke(target, args); after(); return returnValue; } } ); } public void before(){ System.out.println("关注java程序员思维公众号"); } public void after(){ System.out.println("阅读文章"); }}
public class JdkDynamicProxyTest { public static void main(String[] args) { Sourceable sourceable = new Source(); //获得一个代理对象 Sourceable target = (Sourceable) new JdkDynamicProxy(sourceable).getProxyInstance(); target.method(); }}
运行结果:
3.Cglib版动态代理
静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现。
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
Cglib通过子类来实现,则代理类无法代理一些无法重写的方法,如final方法,静态方法。同时代理的类也不能是final类。
增加jar包maven依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version>
</dependency>
public class CglibDynamicProxy implements MethodInterceptor { //维护目标对象 private Object target; public CglibDynamicProxy(Object target) { this.target = target; } //给目标对象创建一个代理对象 public Object getProxyInstance(){ //1.工具类 Enhancer en = new Enhancer(); //2.设置父类 en.setSuperclass(target.getClass()); //3.设置回调函数 en.setCallback(this); //4.创建子类(代理对象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { before(); //执行目标对象的方法 Object returnValue = method.invoke(target, args); after(); return returnValue; } public void before(){ System.out.println("关注java程序员思维公众号"); } public void after(){ System.out.println("阅读文章"); }}
public class CglibDynamicProxyTest { public static void main(String[] args) { Sourceable sourceable = new Source(); Sourceable proxyTarget = (Sourceable) new CglibDynamicProxy(sourceable).getProxyInstance(); proxyTarget.method(); }}
运行结果:
配置aop <aop:config proxy-target-class="true"> true使用cglib产生代理对象,fals使用jdk,默认false。
JDK和框架中的代理模式
spring中的aop切面编程,就是通过动态代理来实现的。
优缺点
优点:开闭原则的情况下对目标对象进行功能扩展。
缺点:1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
生活中的代理模式
产品代理
生活中典型的代理模式就是代理商,化妆品、药品、奶粉只要是产品都有可能存在代理商。小卖部、超市、商场也都是代理,给产品供应商做代理销售,加快产品的销售,但是每经过一次代理商,就有一次利益的分配,产品的价格会有所加成,所以现在很多公司都提倡直销,没有中间商赚差价。
服务代理
现实生活中不仅有产品代理,也有服务代理,像阿里云、电信、百度云等服务,都有相应的代理商,客户通过代理商,可以更省心。
我的启发
猪八戒高老庄找高翠兰,结果是孙悟空变的,猪八戒看不出来,就像看见的是高家大小姐,孙悟空就成了她的代理。代理模式就像百变星君一样,在我们不方便或者不懂的时候,让代理去帮我们完成相应的工作,有时候代理比我们更专业,比我们自己完成的更好。