动态代理模式
< 返回列表时间: 2018-12-24来源:OSCHINA
动态代理模式
在介绍这个模式之前我们,先看看背景需求:
查看工资的需求:进行安全性检查,开启日志记录,(权限判断)如果有权限则查看工资,否则提示无权限。
通常的实现方式
安全性框架检查类: public class Security { public void security(){ System.out.println("checking security...."); } }
日志记录 public class Logger { public void log() { System.out.println("starting log...."); } }
权限判断 public class Privilege { private String access; public String getAccess() { return access; } public void setAccess(String access) { this.access = access; } }
目标类 public class SalaryManager { private Logger logger; private Privilege privilege; private Security security; public SalaryManager(Security security, Logger log, Privilege privilege) { super(); this.security = security; this.logger = log; this.privilege = privilege; } public void showSalary() { this.security.security(); this.logger.log(); if ("admin".equals(privilege.getAccess())) { System.out.println("这个月工资涨了10%..."); } else { System.out.println("对不起,你无权限查看工资!"); } } }
测试类 public class ShowSalaryTest { [@Test](https://my.oschina.net/azibug) public void test() { Security security = new Security(); Logger log = new Logger(); Privilege privilege = new Privilege(); privilege.setAccess("admin"); SalaryManager sm = new SalaryManager(security,log,privilege); sm.showSalary(); } }
小结:
目标类和一些公共事务耦合在一起了,而且目标类也是被固定写死了,无法做到动态执行某个目标类。其实这类公共的事务:安全性验证,日志记录和权限验证是可以被其他业务(客户)使用的,应该独立出来,达到复用的效果。
手写动态代理
首先将工资管理,即目标类用接口去封装,如下: public interface SalaryManage { // 目标动作 public void showSalary(); }
SalaryManage的实现类 public class SalaryManageImpl implements SalaryManage { [@Override](https://my.oschina.net/u/1162528) public void showSalary() { System.out.println("涨工资了。。。。"); } }
再建立目标类的代理类 /** * 目标类的代理类 * */ public class SalaryManageProxy { private Logger log; private Privilege privilege; private Security security; private SalaryManage salaryManager; public SalaryManageProxy() { super(); } public SalaryManageProxy(Logger log, Privilege privilege, Security security, SalaryManage salaryManager) { super(); this.log = log; this.privilege = privilege; this.security = security; this.salaryManager = salaryManager; } /** * 优点:添加了代理类,将目标类和公共事务分离 * 缺点:代理类的代理方法中目标类和目标方法被固定死了,无法动态变化,不可重用。 */ //代理方法 public void showSalary() { this.log.log(); this.security.security(); if ("admin".equals(privilege.getAccess())) { salaryManager.showSalary();// 目标类的目标方法 } else { System.out.println("对不起,你没有权限访问!"); } } }
测试类: public class ShowSalaryTest { /** * 通过引入代理类,将目标类和公共事务分离 */ [@Test](https://my.oschina.net/azibug) public void test() { Security security = new Security(); Logger log = new Logger(); Privilege privilege = new Privilege(); privilege.setAccess("admin"); SalaryManage sm = new SalaryManageImpl(); /** * 代理类调用代理方法,执行目标类目标方法。达到了预期效果 */ new SalaryManageProxy(log, privilege, security, sm).showSalary();; } }
小结: 优点:添加了代理类,将目标类和公共事务分离 缺点:代理类的代理方法中目标类和目标方法被固定死了,无法动态变化,不可重用。
JDK动态代理
目标类的接口 public interface SalaryManage { // 目标动作 public void showSalary(); }
目标类的实现 public class SalaryManageImpl implements SalaryManage { [@Override](https://my.oschina.net/u/1162528) public void showSalary() { System.out.println("涨工资了。。。。"); } }
拦截器(即代理类) /** * 拦截器,基于实现jdk InvocationHandler 的拦截器 * */ public class SalaryManageJDKProxy implements InvocationHandler{ private Logger log; private Privilege privilege; private Security security; private Object target; public SalaryManageJDKProxy() { super(); } public SalaryManageJDKProxy(Logger log, Privilege privilege, Security security) { super(); this.log = log; this.privilege = privilege; this.security = security; } [@Override](https://my.oschina.net/u/1162528) public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { this.security.security(); this.log.log(); if ("admin".equals(this.privilege.getAccess())) { method.invoke(this.target, args); } else { System.out.println("对不起,你没有权限访问!"); } return null; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } }
测试类 public class JDKProxySalaryTest { @Test public void test() { Security security = new Security(); Logger log = new Logger(); Privilege privilege = new Privilege(); privilege.setAccess("admin"); SalaryManage sm = new SalaryManageImpl(); //拦截器 SalaryManageJDKProxy salaryManageJDKProxy = new SalaryManageJDKProxy(log, privilege, security); salaryManageJDKProxy.setTarget(sm); /** * 生成代理对象 * ClassLoader loader, 目标类的类加载器 * Class<?>[] interfaces,目标类的接口数组 * InvocationHandler h,代理类实例 */ SalaryManage newProxyInstance = (SalaryManage) Proxy.newProxyInstance(SalaryManage.class.getClassLoader(), new Class[] { SalaryManage.class }, salaryManageJDKProxy);//代理对象,被创建的代理对象实现过了目标类的接口 newProxyInstance.showSalary(); } }
小结: 概念:目标类,代理类,拦截器 目标接口,由目标类实现目标接口 目标类和代理类实现了共同的接口
cglib代理模式
需求说明:模拟hibernate编程 开启事务 进行增删改查(目标类的目标方法) 结束事务
事务类 public class Transaction { public void beginTransaction() { System.out.println("begin transaction"); } public void commit() { System.out.println("commit"); } }
Dao类 public class PersonDao { public void updatePerson() { System.out.println("update person"); } public void addPerson() { System.out.println("add person"); } public void deletePerson() { System.out.println("delete person"); } public void listPersons() { System.out.println("list person"); } }
拦截类 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 PersonDaoInterceptor implements MethodInterceptor { private Transaction transaction; private Object target; public PersonDaoInterceptor(Transaction transaction, Object target) { super(); this.transaction = transaction; this.target = target; } /** * 产生代理对象 * @return */ public Object createProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass());//设置目标类为代理类的父类 enhancer.setCallback(this);//设置拦截器为回调函数 return enhancer.create(); } @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { Object obj; String methodName = method.getName(); if ("updatePerson".equals(methodName) || "addPerson".equals(methodName) || "deletePerson".equals(methodName)) { //开启事务 this.transaction.beginTransaction(); //调用目标类的目标方法 obj = method.invoke(this.target, args); //做是否提交事务 this.transaction.commit(); } else { //调用目标类的目标方法 obj = method.invoke(this.target, args); } return obj; } public Transaction getTransaction() { return transaction; } public void setTransaction(Transaction transaction) { this.transaction = transaction; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } }
测试类: import org.junit.Test; public class PersonDaoTest { @Test public void test() { Transaction transaction = new Transaction(); PersonDao personDao = new PersonDao(); PersonDaoInterceptor inteceptor = new PersonDaoInterceptor(transaction,personDao); //代理类是目标类的子类。 PersonDao proxy = (PersonDao)inteceptor.createProxy(); proxy.addPerson(); } }
总结 概念:目标类,代理类,拦截器 jdk: 目标类和代理类实现了共同的接口 拦截器必须实现jdk提供的InvocationHandler,而这个接口中的invoke方法体内容=代理对象方法体内容 当客户端用代理对象调用方法时,invoke方法执行 cglib: 目标类是代理类的父类 拦截器实现了MethodInterceptor,而接口中的intercept方法=代理对象方法体 使用字节码增强机制创建代理对象
热门排行