设计模式_代理模式_由浅入深
来源:互联网 发布:博库数据服务平台 编辑:程序博客网 时间:2024/05/01 20:02
核心目标:
以最小的代价给目标方法加上前置和后置处理功能。
比如某账本类的查询方法,想在查询前增加鉴权,和查询后记录查询日志。
基本原理:
在目标类前面加一个代理类,将直接调用目标方法改为调用代理类的同名方法,再由代理类的同名方法调用目标方法,前/后置逻辑写在代理类的同名方法中。
//TO-DO 添加示意图
核心理论和技术:
1、代理模式
2、反射
3、JDK动态代理
4、Cglib动态代理
5、spring AOP面向切面编程
6、回调模式
技术实现举例:逻辑由易至难,开发由难至易
以账本为例,具有查询和更新两个方法,要在这两个方法前后加上前置和后置处理
IAccount接口:
package com.common;public interface IAccount {public void queryAccount();public void updateAccount();}
AccountImpl1实现:
package com.common;public class AccountImpl1 implements IAccount {public void queryAccount() {System.out.println("查询账户.......");}public void updateAccount() {System.out.println("更新账户......");}}
AccountImpl2实现2:
package com.common;public class AccountImpl2 implements IAccount {public void queryAccount() {System.out.println("当前账户名为:匿名账户");}public void updateAccount() {System.out.println("更新账户名为:张三");}}菜鸟:天下无招
设计思路:
修改账本实现类
新增两个方法:前置方法、后置方法
在执行查询和更新前后,调用前置和后置方法
package com.general;import com.common.IAccount;public class AccountImpl implements IAccount {public void queryAccount() {beforeOperate();System.out.println("查询账户.......");afterOperate();}public void updateAccount() {beforeOperate();System.out.println("更新账户......");afterOperate();}public void beforeOperate(){System.out.println("前置处理.....");}public void afterOperate(){System.out.println("后置处理.....");}}
优点:
逻辑简单,不费脑
缺点:
核心业务代码与辅助性代码高耦合
前置和后置属于通用代码,调用代码重复开发
前后置内容容易随需求发生改变,代码修改会造成核心业务风险
大虾:静态代理,看到武功秘籍,功力大增
设计思路:
1、使用代理设计模式
2、新增代理,即新增一个跟被代理账本1实现了相同账本接口的代理类,具备相同的方法
3、绑定代理关系,即将被代理的账本实现类作为自身的一个属性
4、代理类新增前置和后置处理方法
5、强化需要被代理的方法,即真正的业务处理仍由被代理的对方受理,但在将请求转发给被代理对象之前和之后,分别加上前置和后置处理逻辑
6、修改业务调用逻辑,即将直接调用被代理对象的方法,改为调用代理类的同名方法
package com.staticProxy.staticProxy1;import com.common.AccountImpl1;import com.common.IAccount;public class AccountProxy1 implements IAccount{private AccountImpl1 accountImpl;public AccountProxy1(AccountImpl1 accountImpl){this.accountImpl=accountImpl;}public void queryAccount() {beforeOperate();accountImpl.queryAccount();afterOperate();System.out.println();}public void updateAccount() {beforeOperate();accountImpl.updateAccount();afterOperate();System.out.println();}public void beforeOperate(){System.out.println("前置处理.....");}public void afterOperate(){System.out.println("后置处理.....");}public AccountImpl1 getAccountImpl() {return accountImpl;}public void setAccountImpl(AccountImpl1 accountImpl) {this.accountImpl = accountImpl;}}
测试:
package com.staticProxy.staticProxy1;import com.common.AccountImpl1;import com.common.IAccount;public class test {public static void main(String[] args) {AccountImpl1 accountImpl=new AccountImpl1();IAccount account=new AccountProxy1(accountImpl);account.queryAccount();account.updateAccount();}}
若再来一个账本实现类,则有需要写一个代理类,而且除了代理的实现类不一样外,其余全部一样
package com.staticProxy.staticProxy2;import com.common.AccountImpl2;import com.common.IAccount;public class AccountProxy2 implements IAccount{private AccountImpl2 accountImpl;public AccountProxy2(AccountImpl2 accountImpl){this.accountImpl=accountImpl;}public void queryAccount() {beforeOperate();accountImpl.queryAccount();afterOperate();System.out.println();}public void updateAccount() {beforeOperate();accountImpl.updateAccount();afterOperate();System.out.println();}public void beforeOperate(){System.out.println("前置处理.....");}public void afterOperate(){System.out.println("后置处理.....");}public AccountImpl2 getAccountImpl() {return accountImpl;}public void setAccountImpl(AccountImpl2 accountImpl) {this.accountImpl = accountImpl;}}
测试:
package com.staticProxy.staticProxy2;import com.common.AccountImpl2;import com.common.IAccount;public class test {public static void main(String[] args) {AccountImpl2 accountImpl=new AccountImpl2();IAccount account=new AccountProxy2(accountImpl);account.queryAccount();account.updateAccount();}}
优点:
1、前后置辅助代码跟业务代码完全解耦
2、修改前后置方法不影响原核心业务
缺点:
1、每代理一个类,就得新增一个代理类,开发量大
2、需要修改被代理方法的调用代码,若被调用的地方很多,改造量大
牛人:动态代理,悟性高,会借力
设计思路:
1、代理模式必备要素:要实现代理模式,抽象出来无外乎五样东西
1.1 有一个代理类,用于写前置和后置处理方法
1.2 有一个被代理类,不关心具体是什么,以object抽象
1.3 需要绑定代理关系,即将被代理类跟代理类绑定
1.4 需要知道被强化的方法,不关心具体方法名,以method抽象,不关心传入参数,以args[]抽象,不关心返回参数,以object抽象,可以通过反射来调用
1.5 每个被代理对象需要一个专用的前置代理实例,不关心代理实例是否有真身(java类),只要存在于内存中,具备被代理对象的所有方法即可
1.6 代理实例的方法不需实现任何业务逻辑,只需要接收调用请求,拿到被调用的方法名、参数即可,然后将方法、参数和代理实例本身,传给代理类的回调函数,使用反射原理统一加强处理
2、动态代理简要流程
2.1 生成代码已有两套现成的,直接拿来用
2.1.1 jdk动态代理,只能给实现了接口的类动态生成代理(java自带,所以首选该方案)
2.1.2 Cglib动态代理,能给没有实现接口的类动态生成代理,实现接口的也支持(第三方代码,所以次选)
全称Code generation library 代码生成类库
2.2 生成流程
2.2.1 代理类和被代理类绑定(属性)
2.2.2 使用jdk或者Cglib,根据代理类、被代理类、回调方法,动态生成一个代理实例,该实例只存在于内存中,负责具体的代理工作
2.2.3 动态生成的代理实例,具有被代理对象的所有方法,该方法被调用时,会回调预设的回调方法(jdk是invoke(),Cglib是intercept())
2.2.3 代理类需要有一个回调方法,该方法实现被代理方法的强化,即加上前置后后置方法
借助JDK动态代理(被代理的类必须实现接口)
package com.jdkDynamicProxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class AccountJdkDynamicProxy implements InvocationHandler{private Object proxyedObject;public Object getProxy(Object proxyedObject){this.proxyedObject=proxyedObject;return Proxy.newProxyInstance(proxyedObject.getClass().getClassLoader(), proxyedObject.getClass().getInterfaces(), this);}public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {beforeOperate();Object result=method.invoke(proxyedObject, args);afterOperate();System.out.println();return result;}public void beforeOperate(){System.out.println("前置处理.....");}public void afterOperate(){System.out.println("后置处理.....");}public Object getProxyedObject() {return proxyedObject;}public void setProxyedObject(Object proxyedObject) {this.proxyedObject = proxyedObject;}}
测试:写一次代理类,动态代理多个实现类
package com.jdkDynamicProxy;import com.common.AccountImpl1;import com.common.AccountImpl2;import com.common.IAccount;public class test1 {public static void main(String[] args) {AccountJdkDynamicProxy proxy=new AccountJdkDynamicProxy();/*代理账本1*/IAccount account=new AccountImpl1();IAccount accountProxy=(IAccount)proxy.getProxy(account);accountProxy.queryAccount();accountProxy.updateAccount();/*代理账本2*/account=new AccountImpl2();accountProxy=(IAccount)proxy.getProxy(account);accountProxy.queryAccount();accountProxy.updateAccount();}}
借Cglib动态代理(不要求被代理的类必须实现接口)
package com.cglibDynamicProxy;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 AccountCglibDynamicProxy implements MethodInterceptor {private Object proxyedObject;public Object getProxy(Object proxedObject){this.proxyedObject=proxedObject;Enhancer enhancer=new Enhancer();enhancer.setSuperclass(proxyedObject.getClass());enhancer.setCallback(this);return enhancer.create();}public Object intercept(Object arg0, Method arg1, Object[] arg2,MethodProxy proxy) throws Throwable {beforeOperate();Object result=proxy.invokeSuper(arg0, arg2);afterOperate();System.out.println();return result;}public void beforeOperate(){System.out.println("前置处理.....");}public void afterOperate(){System.out.println("后置处理.....");}public Object getProxyedObject() {return proxyedObject;}public void setProxyedObject(Object proxyedObject) {this.proxyedObject = proxyedObject;}}测试:
package com.cglibDynamicProxy;import com.common.AccountImpl2;import com.common.AccountImpl4;public class test {public static void main(String[] args) {/*使用代理_非接口类*/AccountCglibDynamicProxy proxy=new AccountCglibDynamicProxy();AccountImpl4 account=new AccountImpl4();AccountImpl4 accountProxy=(AccountImpl4)proxy.getProxy(account);accountProxy.queryAccount();accountProxy.updateAccount();/*使用代理_接口类*/AccountImpl2 account2=new AccountImpl2();AccountImpl2 accountProxy2=(AccountImpl2)proxy.getProxy(account2);accountProxy2.queryAccount();accountProxy2.updateAccount();}}
优点:
代理类只需写一份,具体被代理的代理实例动态生成,开发量小
缺点:
1、接口类和非接口类,需要不同的实现
2、依赖于JDK和Cglib的代理规范,属于重开发
3、代理类编写复杂,技术要求高,未实现POJO编程
4、被代理对象的所有方法均被代理,可自定义程度低
大牛:拳无拳意无意,无意之中是真意:Spring的AOP面向切面编程
设计思路:
1、spring的POJO编程思想,即Plain Ordinary Java Object简单的Java对象
2、业务类,就写业务方法
3、代理类,就写前置和后置方法
4、依赖关系由xml配置文件维护
5、spring封装jdk和cglib,对用户不可见
代理类:
package com.springDynamicProxy;public class AspectBean {public void beforeOperate(){System.out.println("前置处理.....");}public void afterOperate(){System.out.println("后置处理.....");}}
代理关系注册:
<?xml version="1.0" encoding="utf-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"><bean id="accountImpl1" class="com.common.AccountImpl1" /><bean id="accountImpl4" class="com.common.AccountImpl4" /><bean id="aspectBean" class="com.springDynamicProxy.AspectBean" /><!-- 对Test类进行AOP拦截 --><aop:config><aop:aspect id="TestAspect" ref="aspectBean"><!--配置切面--><aop:pointcut id="businessService"expression="(execution(* com.common.AccountImpl1.queryAccount(..))) or (execution(* com.common.AccountImpl4.queryAccount(..)))"/><aop:before pointcut-ref="businessService" method="beforeOperate" /><aop:after pointcut-ref="businessService" method="afterOperate" /></aop:aspect></aop:config></beans>
测试:
package com.springDynamicProxy;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.common.AccountImpl4;import com.common.IAccount;public class test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("com/springDynamicProxy/test.xml");/*接口类:使用JDK代理*/IAccount accountImpl1=(IAccount) ctx.getBean("accountImpl1");System.out.println(accountImpl1.getClass().getSimpleName());System.out.println("super class is "+accountImpl1.getClass().getSuperclass());accountImpl1.queryAccount();/*非接口类:使用Cglib代理*/AccountImpl4 accountImpl4=(AccountImpl4)ctx.getBean("accountImpl4");System.out.println(accountImpl4.getClass().getSimpleName());System.out.println("super class is "+accountImpl4.getClass().getSuperclass());accountImpl4.queryAccount();}}
优点:
1、不直接依赖于JDK和Cglib的规范,真正实现POJO编程
2、代理关系统一配置,维护简单,使用灵活
3、代理类编写简单,开发量小
- 设计模式_代理模式_由浅入深
- 设计模式_代理模式
- 设计模式_代理模式
- 设计模式_代理模式
- (GOF23设计模式)_代理模式_动态代理
- (GOF23设计模式)_代理模式_静态代理
- 大话设计模式_代理模式
- 设计模式学习_代理模式
- 设计模式07_代理模式
- 设计模式_之代理模式
- java设计模式_代理模式
- 设计模式_代理模式(Proxy)
- 设计模式_代理模式(Java)
- 设计模式_ 代理模式(11)
- Java设计模式_(结构型)_代理模式
- 设计模式之代理模式(由浅入深)
- 黑马程序员_代理设计模式
- java设计模式_动态代理(dynamicProxy)
- Jeecms之new标签实现
- Jeecms之编辑器表格对齐及图片插入
- Jeecms之编辑器表格对齐及图片插入
- Jeecms之JSP访问action类
- Eclipse下使用Subversion(SVN工具)
- 设计模式_代理模式_由浅入深
- Java类之间的数据传递3中方法。
- 一个卫语句
- 求两个字符串去掉重复字母后所包含字符
- ROSCORE 失败解决方法
- datagrid 动态生成列
- debian软件源source.list文件格式说明
- HDOJ-1272 小希的迷宫
- 算法题——确定两串乱序同构