AOP的另一种实现----cglib

 大家都知道,动态代理能够实现AOP,但是它有一个缺点,就是所有被代理的对象必须实现一个接口,否则就会报异常。那么如果被代理对象没有实现接口那该如何实现AOP呢?当然是能的,使用CGlib就可以实现。

1、什么是CGlib

  CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。 然这些实际的功能是asm所提供的,asm又是什么?Java字节码操控框架,具体是什么大家可以上网查一查,毕竟我们这里所要讨论的是cglib, cglib就是封装了asm,简化了asm的操作,实现了在运行期动态生成新的class。 可能大家还感觉不到它的强大,现在就告诉你。 实际上CGlib为spring aop提供了底层的一种实现;为hibernate使用cglib动态生成VO/PO (接口层对象)。

  它的原理就是用Enhancer生成一个原有类的子类,并且设置好callback , 则原有类的每个方法调用都会转成调用实现了MethodInterceptor接口的proxy的intercept() 函数: 
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) 
 
 在intercept()函数里,你可以在执行Object
result=proxy.invokeSuper(o,args);来执行原有函数,在执行前后加入自己的东西,改变它的参数,也可以瞒天过海,完全干
别的。说白了,就是AOP中的around advice。

  2、如何使用CGlib

  举个例子:比如DAO层有对表的增、删、改、查操作,如果要对原有的DAO层的增、删、改、查增加权限控制的话,修改代码是非常痛苦的。所以可以用AOP来实现。但是DAO层没有使用接口,动态代理不可用。这时候CGlib是个很好的选择。

TableDao.java:

 1 package com.cglib;
 2
 3 public class TableDao {
 4     public void create(){
 5         System.out.println(“create() is running…”);
 6     }
 7     public void delete(){
 8         System.out.println(“delete() is running…”);
 9     }
10     public void update(){
11         System.out.println(“update() is running…”);
12     }
13     public void query(){
14         System.out.println(“query() is running…”);
15     }
16 }

实现了MethodInterceptor接口的AuthProxy.java:用来对方法进行拦截,增加方法访问的权限控制,这里只允许张三访问。

 1 package com.cglib;
 2
 3 import java.lang.reflect.Method;
 4
 5 import net.sf.cglib.proxy.MethodInterceptor;
 6 import net.sf.cglib.proxy.MethodProxy;
 7 //方法拦截器
 8 public class AuthProxy implements MethodInterceptor {
 9     private String userName;
10     AuthProxy(String userName){
11         this.userName = userName;
12     }
13     //用来增强原有方法
14     public Object intercept(Object arg0, Method arg1, Object[] arg2,
15             MethodProxy arg3) throws Throwable {
16         //权限判断
17         if(!”张三”.equals(userName)){
18             System.out.println(“你没有权限!”);
19             return null;
20         }
21         return arg3.invokeSuper(arg0, arg2);
22     }
23 }

TableDAOFactory.java:用来创建TableDao的子类的工厂类

 1 package com.cglib;
 2
 3 import net.sf.cglib.proxy.Callback;
 4 import net.sf.cglib.proxy.Enhancer;
 5 import net.sf.cglib.proxy.NoOp;
 6
 7 public class TableDAOFactory {
 8     private static TableDao tDao = new TableDao();
 9     public static TableDao getInstance(){
10         return tDao;
11     }
12     public static TableDao getAuthInstance(AuthProxy authProxy){
13         Enhancer en = new Enhancer();  //Enhancer用来生成一个原有类的子类
14         //进行代理
15         en.setSuperclass(TableDao.class);
16         //设置织入逻辑
17         en.setCallback(authProxy);
18         //生成代理实例
19         return (TableDao)en.create();
20     }
21  }

测试类Client.java:

 1 package com.cglib;
 2
 3 public class Client {
 4
 5     public static void main(String[] args) {
 6 //        haveAuth();
 7         haveNoAuth();
 8     }
 9     public static void doMethod(TableDao dao){
10         dao.create();
11         dao.query();
12         dao.update();
13         dao.delete();
14     }
15     //模拟有权限
16     public static void haveAuth(){
17         TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy(“张三”));
18         doMethod(tDao);
19     }
20     //模拟无权限
21     public static void haveNoAuth(){
22         TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy(“李四”));
23         doMethod(tDao);
24     }
25 }

  这样就能够对DAO层的方法进行权限控制了。但是如果又改需求了,要把DAO层的query方法让所有用户都可以访问,而其他方法照样有权限控制,该如何实现呢?这可难不倒我们了,因为我们使用了CGlib。当然最简单的方式是去修改我们的方法拦截器,不过这样会使逻辑变得复杂,且不利于维护。还好CGlib给我们提供了方法过滤器(CallbackFilter),CallbackFilte可以明确表明,被代理的类中不同的方法, 被哪个拦截器所拦截。下面我们就来做个过滤器用来过滤query方法。 

AuthProxyFilter.java:

 1 package com.cglib;
 2
 3 import java.lang.reflect.Method;
 4
 5 import net.sf.cglib.proxy.CallbackFilter;
 6 import net.sf.cglib.proxy.NoOp;
 7
 8 public class AuthProxyFilter implements CallbackFilter {
 9
10     public int accept(Method arg0) {
11         /
12           如果调用的不是query方法,则要调用authProxy拦截器去判断权限
13          /
14         if(!”query”.equalsIgnoreCase(arg0.getName())){
15             return 0; //调用第一个方法拦截器,即authProxy
16         }
17         /
18           调用第二个方法拦截器,即NoOp.INSTANCE,NoOp.INSTANCE是指不做任何事情的拦截器
19           在这里就是任何人都有权限访问query方法,所以调用默认拦截器不做任何处理
20          */
21         return 1;
22     }
23
24 }

  至于为什么返回0或者1,注释讲的很详细。

在TableDAOFactory.java里添加如下方法:

1 public static TableDao getAuthInstanceByFilter(AuthProxy authProxy){
2         Enhancer en = new Enhancer();
3         en.setSuperclass(TableDao.class);
4         en.setCallbacks(new Callback[]{authProxy,NoOp.INSTANCE});  //设置两个方法拦截器
5         en.setCallbackFilter(new AuthProxyFilter());
6         return (TableDao)en.create();
7     }  

 
 这里得注意,en.setCallbacks()方法里的数组参数顺序就是上面方法的返回值所代表的方法拦截器,如果return
0则使用authProxy拦截器,return
1则使用NoOp.INSTANCE拦截器,NoOp.INSTANCE是默认的方法拦截器,不做什么处理。

  下面在测试类中添加如下方法:

1 //模拟权限过滤器
2     public static void haveAuthByFilter(){
3         TableDao tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy(“张三”));
4         doMethod(tDao);
5         tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy(“李四”));
6         doMethod(tDao);
7     }  

在main方法中调用该方法,程序运行结果如下:

create() is running…
query() is running…
update() is running…
delete() is running…
你没有权限!
query() is running…
你没有权限!
你没有权限!

  这样的话,所有用户都对query方法有访问权限了,而其他方法只允许张三访问。

时间: 2024-09-16 09:46:50

AOP的另一种实现----cglib的相关文章

小结.NET中实现AOP开发的七种方法

在这里列表了我想到的在你的应用程序中加入AOP支持的所有方法.这里最主要的焦点是拦截,因为一旦有了拦截其它的事情都是细节. Approach 方法 Advantages 优点 Disadvantages 缺点 Remoting Proxies 远程代理 Easy to implement, because of the .Net framework support 容易实现,因为有.NET 框架的支持. Somewhat heavy weight Can only be used on inte

java版云笔记(六)之AOP

今天主要是利用aop技术追加service的响应时间的计算和异常的日志记录. AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面. AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程中的步骤进行抽象,从而获得步骤

Spring中的AOP(一)——AspectJ的基本使用

    AOP(Aspect Orient Programming),也就是面向切面编程,作为面向对象编程的一种补充,当前已经成为一种比较成熟的编程思想,其实AOP问世的时间并不长,甚至在国内的翻译还不太统一(另有人翻译为"面向方面编程").AOP和OOP(Object Orient Programming,面向对象编程)互为补充,OOP将程序分解成各个层次的对象,而AOP则将程序运行过程分解成各个切面.可以这样理解:OOP是从静态角度考虑程序结构,而AOP则从动态角度考虑程序运行过程

【框架】[Spring] 基于Spring框架的Web应用演示(附带cglib工具进行动态代理)

转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 前言: Spring也差不多学了Ioc控制反转和实现AOP技术的两种方式了,分享一个学习Spring,用来入门挺好的例子. 如果你是刚刚学习Spring,那么此实例应该可以很好的帮助你应用Spring到Web项目中. 里面的DAO层-提交数据库的事务我并没有使用Spring 的注解功能,而是用spring的AOP来实现的.这样更灵活,其实,框架为我们做的事越多,我们就越受框架的约束

什么是AOP系列之一:AOP概念解析

概念 为什么要区分J2EE容器和J2EE应用系统? 我们知道,J2EE应用系统只有部署在J2EE容器中才能运行,那么为什么划分为J2EE容器和J2EE应用系统? 通过对J2EE容器运行机制的分析,我们可以发现:实际上J2EE容器分离了一般应用系统的一些通用功能,例如事务机制.安全机制以及对象池或线程池等性能优化机制. 这些功能机制是每个应用系统几乎都需要的,因此可以从具体应用系统中分离出来,形成一个通用的框架平台,而且,这些功能机制的设计开发有一定难度,同时运行的稳定性和快速性都非常重要,必须经

C#用delegate实现AOP事务[C# | AOP | delegate]

前言 上一篇 C# 用Attribute实现AOP事务 [C# | AOP | Attribute | ContextAttribute | IContributeObjectSink | IMessageSink ]是实现或者说达到AOP效果的一种方式,其实最早设计在C#中使用AOP来完成事务的方案是准备用delegate的,但无奈不习惯用 这个玩意,也理解不深,后来被Attribute吸引了,这个方案就搁浅了,不过现在我又回来了 : ) 正文 我们先来看一段代码雏 形: class Test

AOP概念解析

为什么要区分J2EE容器和J2EE应用系统? 我们知道,J2EE应用系统只有部署在J2EE容器中才能运行,那么为什么划分为J2EE容器和J2EE应用系统? 通过对J2EE容器运行机制的分析,我们可以发现:实际上J2EE容器分离了一般应用系统的一些通用功能,例如事务机制.安全机制以及对象池或线程池等性能优化机制. 这些功能机制是每个应用系统几乎都需要的,因此可以从具体应用系统中分离出来,形成一个通用的框架平台,而且,这些功能机制的设计开发有一定难度,同时运行的稳定性和快速性都非常重要,必须经过长时

举例讲解Java的Spring框架中AOP程序设计方式的使用_java

1.什么是AOP AOP是Aspect Oriented Programming的缩写,意思是面向方面编程,AOP实际是GoF设计模式的延续. 2.关于Spring AOP的一些术语: A.切面(Aspect):在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect 注解(@AspectJ风格)来实现 B.连接点(Joinpoint):在Spring AOP中一个连接点代表一个方法的执行 C.通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作.通

spring学习笔记(13)基于Schema配置AOP详解

基于Schema配置入门实例 除了基于@AspectJ注解的形式来实现AOP外,我们还可以在IOC容器中配置.先来看看一个常见的应用场景,在我们的web项目中,我们需要为service层配置事务,传统的做法是在每个业务逻辑方法重复下面配置中: Created with Raphaël 2.1.0程序开始1. 获取DAO层封装好的数据库查询API,如HIbernate中的SessionFactory/Session和mybatis中的xxxMapper2. 开启事务3. 根据入参查询数据库完成相应