AOP/CGLIB学习:实现简单的注解权限系统(Annotation+拦截器)
来源:互联网 发布:潍坊网络广播电视台 编辑:程序博客网 时间:2024/05/19 17:48
注: 本文只是原理性质, 并不实用, 读者可用成熟稳定的开源权限系统如SpringSecurity. 但可参考实现自己的一些小框架.
在上课的时候, 一位同学拿着一篇JavaEye的很长的CGLIB讲解代码来问我这是怎么回事?我看了下, 觉得那样的例子实在太让人难以一下子看懂了, 于是就自己重造了个轮子.
Spring 2.5最大的亮点就是基于注解实现配置, 其实这个谈不上什么亮点, EJB3/JPA早就实现了, 而且在原理上也只是利用反射里面的method.getAnnotation(MyAnnotaion.class)即可.
第二个一直大张旗鼓吹捧的就是AOP, 其实AOP就是个JDK接口方法拦截器/子类增强, 不过Spring加了个配置文件封装, 而且和它的一贯作风一致, 都是集成第三方的框架, 这里基于类增强的是CGLIB.
CGLIB是什么呢?
cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime. See samples and API documentation to learn more about features.
This library is free software, freely reusable for personal or commercial purposes.
cglib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java 接口. 而CGLIB本身又用了ASM框架, 来避免直接解析字节码.
OK, 废话少说, 我们来通过一个例子看看基于注解和AOP的权限系统(本代码只需要CGLIB及其依赖类库ASM, 或者直接下载cglib-nodep-2.2.jar http://sourceforge.net/project/showfiles.php?group_id=56933&package_id=98218&release_id=601998).
先看业务层:
基本上就是普通的方法加上了角色注解, 当然注解类也是我们自己写的:
所有的Magic都在后台通过反射和CGLIB的方法拦截器来实现, 先通过JDK本身的反射来检查注解, 然后读取注解的值, 随后进行判断并决定是否执行此方法, 如果中间加上Spring容器, 那就是实现了所谓的专门的权限控制Bean了. 代码:
代码末尾的类A和A_proxy试图说明代理这种模式的实现方式. OK, 运行代码, 应该可以得到我们期望的结果了. admin方法执行成功, 而另一个则失败了.
运行输出:
即将调用方法public void MyClass.setRole(java.lang.String)
发现方法setRole 没有角色限制
即将调用方法public java.lang.String MyClass.adminMethod(java.lang.String)
发现方法上adminMethod 有一个注解 Role, 它的值是admin
即将调用方法public java.lang.String MyClass.getRole()
发现方法getRole 没有角色限制
MyClass.adminMethod()名字
已经调用了方法, 原本应该返回的值:adminMethod 结果
adminMethod 结果
即将调用方法public java.lang.String MyClass.guestMethod(java.lang.String)
发现方法上guestMethod 有一个注解 Role, 它的值是guest
即将调用方法public java.lang.String MyClass.getRole()
发现方法getRole 没有角色限制
对不起, 您的权限不足, 不能调用此方法!
Exception in thread "main" java.lang.Exception: 对不起, 您的权限不足, 不能调用此方法!
at Main$MethodInterceptorImpl.intercept(Main.java:60)
at MyClass$$EnhancerByCGLIB$$e6aea994.guestMethod(<generated>)
at Main.main(Main.java:20)
小结: 基于类的权限系统可通过CGLIB/AOP实现; 基于URL的权限系统可通过过滤器实现. 其实, Servlet的Filter也是AOP的一种基于Web的实现.
在上课的时候, 一位同学拿着一篇JavaEye的很长的CGLIB讲解代码来问我这是怎么回事?我看了下, 觉得那样的例子实在太让人难以一下子看懂了, 于是就自己重造了个轮子.
Spring 2.5最大的亮点就是基于注解实现配置, 其实这个谈不上什么亮点, EJB3/JPA早就实现了, 而且在原理上也只是利用反射里面的method.getAnnotation(MyAnnotaion.class)即可.
第二个一直大张旗鼓吹捧的就是AOP, 其实AOP就是个JDK接口方法拦截器/子类增强, 不过Spring加了个配置文件封装, 而且和它的一贯作风一致, 都是集成第三方的框架, 这里基于类增强的是CGLIB.
CGLIB是什么呢?
cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime. See samples and API documentation to learn more about features.
This library is free software, freely reusable for personal or commercial purposes.
cglib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java 接口. 而CGLIB本身又用了ASM框架, 来避免直接解析字节码.
OK, 废话少说, 我们来通过一个例子看看基于注解和AOP的权限系统(本代码只需要CGLIB及其依赖类库ASM, 或者直接下载cglib-nodep-2.2.jar http://sourceforge.net/project/showfiles.php?group_id=56933&package_id=98218&release_id=601998).
先看业务层:
- public class MyClass {
- private String role;// 运行时角色
- public String getRole() {
- return role;
- }
- public void setRole(String role) {
- this.role = role;
- }
- @Role(name="admin")
- public String adminMethod(String name) {
- System.out.println("MyClass.adminMethod()" + name);
- return "adminMethod 结果";
- }
- @Role(name="guest")
- public String guestMethod(String name) {
- System.out.println("MyClass.guestMethod()" + name);
- return "guestMethod 结果";
- }
- }
基本上就是普通的方法加上了角色注解, 当然注解类也是我们自己写的:
- import java.lang.annotation.*;
- @Documented
- @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})//指定目标, 必须包含方法
- @Retention(RetentionPolicy.RUNTIME)//设置保持性
- @Inherited
- public @interface Role {
- String name();
- }
所有的Magic都在后台通过反射和CGLIB的方法拦截器来实现, 先通过JDK本身的反射来检查注解, 然后读取注解的值, 随后进行判断并决定是否执行此方法, 如果中间加上Spring容器, 那就是实现了所谓的专门的权限控制Bean了. 代码:
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodProxy;
- import net.sf.cglib.proxy.MethodInterceptor;
- public class Main {
- public static void main(String[] args) {
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(MyClass.class);
- enhancer.setCallback( new MethodInterceptorImpl() );
- MyClass my = (MyClass)enhancer.create();
- my.setRole("admin");
- System.out.println(my.adminMethod("名字"));// 这一行将会执行通过
- System.out.println(my.guestMethod("名字"));// 这一行将会执行失败
- /* --> new 父类 --> obj -->
- * MyClass_proxy
- * MyClass obj = new MyClass();// 本来父类
- * MethodInterceptor interceptor;
- public String method(String name) {
- Object value = interceptor.intercept(obj, ojb.getClass().getMethod("method"), new Object[] {name},
- proxy);
- if(value != null) {
- return value;
- }
- return obj.method(name);
- }
- */
- }
- private static class MethodInterceptorImpl implements MethodInterceptor {
- // obj => 父类的实例, method是被调用的方法, args = {String name}, proxy 专门执行方法的工具类
- public Object intercept(Object obj,
- Method method,
- Object[] args,
- MethodProxy proxy) throws Throwable {
- System.out.println("即将调用方法" + method);
- // 检查是否有Role注解 @Role(name="角色名")
- Role role = method.getAnnotation(Role.class);
- if(role != null) {
- // 有注解
- System.out.println("发现方法上" +method.getName() + " 有一个注解 Role, 它的值是" + role.name());
- // 把被调用对象类型还原
- MyClass my = (MyClass)obj;
- if(!role.name().equals(my.getRole())) {
- System.err.println("对不起, 您的权限不足, 不能调用此方法!");
- throw new Exception("对不起, 您的权限不足, 不能调用此方法!");
- }
- else {
- // ojb ==> MyClass my
- // Before
- Object value = proxy.invokeSuper(obj, args);// 正在调用方法
- // invoke 等价于 String return = obj.method(args);
- System.out.println("已经调用了方法, 原本应该返回的值:" + value);
- // After
- return value;
- }
- } else {
- System.out.println("发现方法" +method.getName() + " 没有角色限制");
- Object value = proxy.invokeSuper(obj, args);
- return value;
- }
- }
- }
- class A {
- String a() {
- return "";
- }
- }
- class A_proxy extends A {
- A a = new A();
- String a() {
- String oldValue = a.a();
- return oldValue;
- }
- }
- }
- 另外注解其实是支持数组方式的变量定义的, 那样的话就可以写成:
- @Role(name = {"guest", "admin"})
代码末尾的类A和A_proxy试图说明代理这种模式的实现方式. OK, 运行代码, 应该可以得到我们期望的结果了. admin方法执行成功, 而另一个则失败了.
运行输出:
即将调用方法public void MyClass.setRole(java.lang.String)
发现方法setRole 没有角色限制
即将调用方法public java.lang.String MyClass.adminMethod(java.lang.String)
发现方法上adminMethod 有一个注解 Role, 它的值是admin
即将调用方法public java.lang.String MyClass.getRole()
发现方法getRole 没有角色限制
MyClass.adminMethod()名字
已经调用了方法, 原本应该返回的值:adminMethod 结果
adminMethod 结果
即将调用方法public java.lang.String MyClass.guestMethod(java.lang.String)
发现方法上guestMethod 有一个注解 Role, 它的值是guest
即将调用方法public java.lang.String MyClass.getRole()
发现方法getRole 没有角色限制
对不起, 您的权限不足, 不能调用此方法!
Exception in thread "main" java.lang.Exception: 对不起, 您的权限不足, 不能调用此方法!
at Main$MethodInterceptorImpl.intercept(Main.java:60)
at MyClass$$EnhancerByCGLIB$$e6aea994.guestMethod(<generated>)
at Main.main(Main.java:20)
小结: 基于类的权限系统可通过CGLIB/AOP实现; 基于URL的权限系统可通过过滤器实现. 其实, Servlet的Filter也是AOP的一种基于Web的实现.
后记: 最近网上有一种很普遍的论调, 当大家说XX不好的时候, 有人说XX不行, 有本事你也去跑啊, 去导啊, 不行你就闭嘴. 我想这是一种转移话题的谬论, 举个例子: 如果病人被庸医给看死了, 他的家人是不是还不能说这医生治的不好, 不应该追究责任, 因为他们不会看病啊? 吃菜的不需要会做菜, 但是吃菜的有权利评价菜是否好吃, 所以真正应该闭嘴的是说这种话的人. 所以我们评论框架好坏的时候, 有人就说了: 你说XXX框架不好, 那你有本事也自己去做一个啊; 这是相当荒谬的跑题的论调.
出自:http://jlins.iteye.com/blog/608166
- AOP/CGLIB学习:实现简单的注解权限系统(Annotation+拦截器)
- spring AOP 注解实现登录权限拦截
- 通过cglib实现AOP 拦截器
- 基于 Annotation 拦截的 Spring AOP 权限验证方法
- 基于 Annotation 拦截的 Spring AOP 权限验证方法
- 基于 Annotation 拦截的 Spring AOP 权限验证方法
- 基于 Annotation 拦截的 Spring AOP 权限验证方法
- 基于 Annotation 拦截的 Spring AOP 权限验证方法
- 自定义注解+Struts2拦截器实现简单权限控制
- AOP的实现:Spring注解形式拦截
- 使用拦截器或者AOP实现权限管理(OA系统中实现权限控制)
- 利用注解加拦截器实现struts2的权限设置
- 使用注解(Annotation)实现系统登录检查和权限控制
- 用拦截器,注解实现权限
- 自定义注解+拦截器实现权限控制
- 自定义注解+拦截器实现权限控制
- PHP简单拦截器实现方法【参考java的AOP】
- AOP的另一种实现----cglib
- 幸与不幸的乔布斯童年
- ubuntu10安装samba问题解决
- 一个很有创意 的关于javascript的注释方法
- android中的handler机制详解
- 2012-3-16日总结
- AOP/CGLIB学习:实现简单的注解权限系统(Annotation+拦截器)
- [C] C程序100例_013
- was
- 正则表达式学习笔记---揭开正则表达式的神秘面纱
- GDB 的常用命令 -- 用gdb 跟踪、调试 chromium webkit_unit_tests
- 在struts2.1中使用注解和拦截器实现权限细粒度控制
- 第十七天(C++代码重用II)
- 获取相对路径
- CSDN