动态代理模式
在介绍这个模式之前我们,先看看背景需求:
查看工资的需求:进行安全性检查,开启日志记录,(权限判断)如果有权限则查看工资,否则提示无权限。
通常的实现方式
安全性框架检查类:
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方法=代理对象方法体使用字节码增强机制创建代理对象