博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态代理模式
阅读量:7055 次
发布时间:2019-06-28

本文共 7560 字,大约阅读时间需要 25 分钟。

hot3.png

动态代理模式

在介绍这个模式之前我们,先看看背景需求:

查看工资的需求:进行安全性检查,开启日志记录,(权限判断)如果有权限则查看工资,否则提示无权限。

通常的实现方式

安全性框架检查类:

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方法=代理对象方法体使用字节码增强机制创建代理对象

转载于:https://my.oschina.net/grittan/blog/2992540

你可能感兴趣的文章
转载:分析apk工具aapt的使用,解析其原理
查看>>
如何向视图插入数据
查看>>
注册和策略模式
查看>>
python 列表
查看>>
第七课作业
查看>>
MEAN实践——LAMP的新时代替代方案(下)
查看>>
CentOS7 下安装 Oracle 12c
查看>>
简单介绍AngularJs Filters
查看>>
Python中的dict
查看>>
Beautiful Soup4库文档学习
查看>>
理解cookie和session
查看>>
我的友情链接
查看>>
linux 5,6,9,12单元练习
查看>>
kill命令
查看>>
错题集06
查看>>
磁盘配额限制
查看>>
shell的bash特性
查看>>
HTML中的超链接
查看>>
什么是进程与线程
查看>>
nodeJS之URL
查看>>