小亮同志的疑惑,权限判断代码蛮横地渗透进纯洁的业务逻辑之中,有什么好办法让权限判断走远点呢?
AOP
前传——代理机制
距离产生美……
将logging/Security等周边逻辑等巧妙地分离出主体业务逻辑,一方面让对象责任明确各司其职,提高可维护性;另一方面让它们召之即来挥之即去,修改更加方便。自然先想到Java I/O惯用的Decorate模式。人家早就总结了,叫做“静态代理”,并在此基础上推出了“动态代理”。
要是真用Decorate(静态代理)做权限判断,那乐子可就大了。假设我有五个class,每个class平均有五个函数需要获得相应权限才能进入,那么我就要做五个interface,每个interface平均五个接口函数对应那些函数,另外我需要五个proxy class,这些proxy class要定义对上述每个函数的权限判断包装。Wow,大大不妙,如黑土大叔对白云大妈的抱怨,距离有了,美没了。
而对于Java I/O,接口函数位于底层jdk中,被各种业务逻辑反复调用,且无外乎read/readln/write/writeln等,用Decorate还是值得的。
把目光转向动态代理。首先定义权限控制类RightsSet,每当用户进入系统就会创建该类对象以标示权限:
public
class
RightsSet
...
{ public static final int NO_RIGHT = - 1 ; public static final int LOW_RIGHT = 0 ; public static final int HIGH_RIGHT = 1 ; private String name = " hezh " ; private int right = LOW_RIGHT; public RightsSet(String name, int x) ... { this .name = name; if (x < 5 ) ... { right = NO_RIGHT; } else if (x >= 5 && x < 10 ) ... { right = LOW_RIGHT; } else ... { right = HIGH_RIGHT; } } public boolean isHighRight() ... { return (right == HIGH_RIGHT); } public boolean isLowRight() ... { return (right == LOW_RIGHT); } public String getName() ... { return name; } }
权限定义了三个级别:no-right/low-right/high-right;
业务逻辑的接口IMyBiz:
public
interface
IMyBiz
...
{ public void biz_no_right(); public void biz_low_right(); public void biz_hight_right(); public void biz_no_right1(); public void biz_low_right1(); public void biz_hight_right1(); }
函数名暗含了三种权限,分别为:均可进入/低权限即可进入/高权限方可进入,实现它的业务逻辑如下:
public
class
MyBiz
implements
IMyBiz
...
{ public void biz_no_right() ... { System.out.println( " Any one here " ); } public void biz_low_right() ... { System.out.println( " Some one with low rights here " ); } public void biz_hight_right() ... { System.out.println( " Some one with hight here " ); } public void biz_no_right1() ... { System.out.println( " Any one here 111 " ); } public void biz_low_right1() ... { System.out.println( " Some one with low rights here 111 " ); } public void biz_hight_right1() ... { System.out.println( " Some one with hight here 111 " ); } }
花样在动态代理类中,每当遇到难题,java反射机制总是冲过来排忧解难,这次也不例外。jdk早就在反射中留好了动态代理接口InvocationHandler,我们实现它即可:
public
class
RightHandler
implements
InvocationHandler
...
{ private RightsSet rights_set = null ; private Object delegate = null ; public Object bind(Object delegate, RightsSet rights_set) ... { this .rights_set = rights_set; this .delegate = delegate; return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this ); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable ... { Object result = null ; String[] low_right_methods = ... { " biz_low_right " , " biz_low_right1 " } ; String[] no_right_methods = ... { " biz_no_right " , " biz_no_right1 " } ; String[] high_right_methods = ... { " biz_hight_right " , " biz_hight_right1 " } ; String method_name = method.getName(); for ( int i = 0 ; i < low_right_methods.length; i ++ ) ... { if (method_name.equals(low_right_methods[i])) ... { if (rights_set.isLowRight() || rights_set.isHighRight()) ... { result = method.invoke(delegate, args); } else ... { System.out.println(rights_set.getName() + " 对函数 " + method_name + " 权限不够 " ); } return result; } } for ( int i = 0 ; i < no_right_methods.length; i ++ ) ... { if (method_name.equals(no_right_methods[i])) ... { result = method.invoke(delegate, args); return result; } } for ( int i = 0 ; i < high_right_methods.length; i ++ ) ... { if (method_name.equals(high_right_methods[i])) ... { if (rights_set.isHighRight()) ... { result = method.invoke(delegate, args); } else ... { System.out.println(rights_set.getName() + " 对函数 " + method_name + " 权限不够 " ); } return result; } } return result; } }
其中关键就是用bind函数实现代理和业务逻辑的绑定,用InvocationHandler的接口函数invoke具体实现权限管理以及对业务逻辑开展的影响。测试程序为:
//
No rights-user
System.out.println(
"
For tom...
"
); RightsSet rights_set1
=
new
RightsSet(
"
Tom
"
,
3
); IMyBiz tom_biz
=
(IMyBiz)
new
RightHandler().bind(
new
MyBiz(), rights_set1); tom_biz.biz_hight_right(); tom_biz.biz_low_right(); tom_biz.biz_no_right();
//
Low right-user
System.out.println(
"
For Jerry...
"
); RightsSet rights_set2
=
new
RightsSet(
"
Jerry
"
,
9
); IMyBiz jerry_biz
=
(IMyBiz)
new
RightHandler().bind(
new
MyBiz(), rights_set2); jerry_biz.biz_hight_right1(); jerry_biz.biz_low_right1(); jerry_biz.biz_no_right1();
//
High right-user
System.out.println(
"
For Lucy...
"
); RightsSet rights_set3
=
new
RightsSet(
"
Lucy
"
,
12
); IMyBiz lucy_biz
=
(IMyBiz)
new
RightHandler().bind(
new
MyBiz(), rights_set3); lucy_biz.biz_hight_right1(); lucy_biz.biz_low_right(); lucy_biz.biz_no_right1();
其中Tom是no-right用户,Jerry是low-right用户,Lucy是high-right用户,结果如下:
For tom...
Tom
对函数
biz_hight_right
权限不够
Tom
对函数
biz_low_right
权限不够
Any one here
For Jerry...
Jerry
对函数
biz_hight_right1
权限不够
Some one with low rights here 111
Any one here 111
For Lucy...
Some one with hight here 111
Some one with low rights here
Any one here 111
可以看到三个人权限一个高于一个。
总结一下动态代理的优势:比较好的实现了权限管理等非主体业务逻辑和主体业务逻辑的分离,并将这些非主体逻辑集中到InvocationHandler一并处理(针对静态代理的优势),最终提高了可维护性。
有了点 AOP的影子……