一、什么是代理
代理,是OOP
里面,很重要的一个设计模式,成为代理模式
就是生成一个和真实角色
相同的 代理角色
真实角色
负责自己业务有关的事情
代理角色
负责一些边角的事情,来为真实业务辅助
比如 医生 和 护士
医生算是一个真实角色,护士算是 医生的代理,也就是代理角色
医生做好自己业务的事情,医护患者
护士帮助医生,做其他的事情,比如量体温,助手等
二、代理Demo
2.1、代理工厂ProxyFactory
首先,我们还是遵守工厂模式的思想,先建一个工厂来降低耦合度
/**
* 基于反射的代理工厂
* 封装了一个工具方法,传入一个原始对象,返回代理对象
* @author PigIsDuck
*
*/
public class ProxyFactory {
/**
* 传入一个原始的目标对象,返回一个代理对象
* @param target
* @param interceptorName 拦截器名字
* @return
*/
public static Object bind(Object target, String interceptorName) {
// 1. 获得目标对象的类
Class<? extends Object> clz = target.getClass();
return Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), new ProxyProcessor(target, interceptorName));
}
}
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
ClassLoader loader
: 可以通过目标对象类直接获取Class<?>[] interfaces
:可以通过目标对象类直接获取InvocationHandler h
:代理对象的业务,自己建立使用InvocationHandler
接口
2.2、代理对象的业务类ProxyProcessor
public class ProxyProcessor implements InvocationHandler{
// 目标对象 / 代理对象
private Object target;
public ProxyProcessor() {
}
public ProxyProcessor(Object target) {
this.target = target;
}
/**
* 对代理对象中的所有方法的增强逻辑
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理对象使用方法前");
// 执行目标对象的业务
result = method.invoke(target, args);
System.out.println("在" + new Date() + "\n使用了什么参数:" + Arrays.toString(args) + "\n调用了什么方法:" + method.getName());
System.out.println("代理对象使用方法后");
return result;
}
}
2.3、使用代理执行业务
这个对象是在MVC创建好的项目,我们可以不改变项目的代码,来添加项目执行时的 代理对象的业务
public static void main(String[] args) {
// 获取类
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userServiceImpl");
// 代理对象
UserService userService2 = (UserService) ProxyFactory.bind(userService);
System.out.println("users:" + userService2.queryAllUser());
}
结果:
init MockServlet1
----------------------------------------------
代理对象使用方法前
net.duck.spring.ioc.dao.UserDao@5d11346a
在Wed Sep 02 18:12:29 CST 2020
使用了什么参数:null
调用了什么方法:queryAllUser
代理对象使用方法后
--------------------------------------------
users:[User [username=duck, password=123456], User [username=pig, password=1asd56]]
我们可以看到,在目标对象本身的业务上,多了一些其他的结果,那些,就是代理对象做的
所以,我们便可以利用这个特点,编写一些功能,如:
- 事务控制
- 日志记录
- 拦截器