动态代理模式

动态代理模式

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

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

通常的实现方式

安全性框架检查类:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值