什么是代理模式
代理模式是一种设计模式,分为静态代理和动态代理两种,当需要在一整套开发流程中嵌入式的增加功能又不改变代码结构的情况下,就可以将一些业务交给代理对象来做,代理模式也是Spring AOP的核心。
以下故事纯属虚构
我们来看以下这个例子,首先我们有一套完整的业务流程(增删改查)。
//接口
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
//实现类
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
这个时候领导突然需要在每一个方法前增加一些操作(手动打一些日志)。
这个时候心想,如此简单的任务,真是太轻松了~~~~~
//错误示范,请勿模仿
public class UserServiceImpl implements UserService{
public void add() {
//假装是日志
System.out.println("使用了add方法");
System.out.println("增加了一个用户");
}
public void delete() {
//假装是日志
System.out.println("使用了delete方法");
System.out.println("删除了一个用户");
}
public void update() {
//假装是日志
System.out.println("使用了update方法");
System.out.println("修改了一个用户");
}
public void query() {
//假装是日志
System.out.println("使用了query方法");
System.out.println("查询了一个用户");
}
}
这个时候,领导又站了出来,这个日志的格式需要换一下,将使用了XXX方法改成调用了XXX方法,看着成百上千的方法,陷入了沉思,Emmm…
果然老话说得好,祖传代码不能碰!
看着这复用率极高的代码,怎么办呢?
静态代理的实现
于是乎,为了将原有的高耦合代码提取出一个类,但是又不改动之前的类,就需要使用代理类来进行操作。
//静态代理
public class UserServiceProxy {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
public void log(String msg){
System.out.println("调用了"+msg+"方法");
}
}
使用这个代理类就可以不改动其他方法的情况下通过代理类调用这些方法了,并解决了日志问题。
Emmm…测试一下
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
果然可以,但是看着成百上千的业务类,每一个类都要写一个代理类,下面这东西好像是写死的。那不是又要写成百上千的代理类来代理业务类
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
一个优秀的程序员是不允许这种高耦合度的代码存在的(这改下来可能要累死)。
沉思中~~~~~
动态代理
要想办法把代理类弄成动态生成的啊!
咦!好像可以通过动态代理来实现
- 实现InvocationHandler接口
- 生成代理类
//用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到的代理类(代理实例在这里被动态生成)
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//通过反射获得方法并通过invoke(反射对象,参数)执行
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
好像是这么回事,测一下…
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色(不存在)
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置代理对象
pih.setTarget(userService);
//动态生成代理实例
UserService proxy = (UserService) pih.getProxy();
proxy.delete();
}
}
输出结果:
执行了delete方法
删除了一个用户
仔细看了看,这个InvocationHandler实现类里面的invoke方法没有调用过啊,结果怎么出来的?
参考jdk帮助文档
因此在proxy代理实例中调用方法的时候,调用了invoke方法。
?????
问号消失了!
动态代理解决了静态代理中每个业务层都需要一个代理类来代理的问题,降低了代码的耦合度。