• (转)使用CGLIB实现AOP功能与AOP概念解释


    http://blog.csdn.net/yerenyuan_pku/article/details/52864395

    使用CGLIB实现AOP功能

    在Java里面,我们要产生某个对象的代理对象,这个对象必须要有一个特点,即这个对象必须实现一个接口,动态代理技术只能基于接口进行代理。有时候我们在做开发的时候,这个对象就没有实现接口,有人可能会说,它既然没有接口,那我就给它定义一个接口,这是不行的,因为有时候我们拿到一个对象,而这个对象是服务器产生给我们的,是服务器提供给我们的,又不是我们自己写的,动不动就给它定义一个接口,给它找个爸爸,哪那行呢?但我们现在要对它进行增强,这时用动态代理技术就不行了,动态代理技术只能是基于接口,那如果这个对象没有接口,又该怎么做呢? 
    那这时我们就需要使用另外一套API——CGLIB了,这套API,即使没有接口,它也可以帮我们产生这个对象的代理对象。它的内部是怎么去产生这个对象的代理对象的呢?——实际上产生的是这个对象的子类,也即我们把一个对象交给CGLIB,它返回出来的似乎是一个代理对象(但它不是要产生一个对象的代理对象),但其实这个代理对象就是这个对象的子类,利用子类的方式来创建代理对象。在Spring里面就是这样做的,Spring里面有一个AOP编程(即面向切面编程,说白了就是动态代理,我们经常会交给Spring一个对象,它就会返回代理对象给我们,它在返回代理对象的时候,首先会检查我们这个对象有没有实现一个接口,如果我们这个类有接口,它使用Java的动态代理技术来帮我们构建出代理对象;如果我们这个类没有实现接口,它会使用CGLIB这套API,采用创建子类的方式来创建代理对象)。 
    本文是建立在使用JDK中的Proxy技术实现AOP功能的案例的基础之上的,若要使用CGLIB这套API实现AOP功能,就要将其所需要的jar包导入项目中,所需的jar包有:

    • asm-2.2.3.jar
    • cglib-nodep-2.2.jar

    首先将PersonServiceBean类的代码修改为:

    public class PersonServiceBean {
        private String user = null;
    
        public String getUser() {
            return user;
        }
    
        public PersonServiceBean() {}
    
        public PersonServiceBean(String user) {
            this.user = user;
        }
    
        public void save(String name) {
            System.out.println("我是save()方法");
        }
    
        public void update(String name, Integer personid) {
            System.out.println("我是update()方法");
        }
    
        public String getPersonName(Integer personid) {
            System.out.println("我是getPersonName()方法");
            return "xxx";
        }
    }

    可发现PersonServiceBean类没实现一个接口,现在要想产生PersonServiceBean类的代理对象,这时就不能不使用CGLIB这套API了。 
    我们在it.cast.aop包下新建一个类——CGlibProxyFactory.java,与JDKProxyFactory类相似,都用于创建代理对象,其代码为:

    public class CGlibProxyFactory implements MethodInterceptor {
        private Object targetObject; // 代理的目标对象
    
        public Object createProxyInstance(Object targetObject) {
            this.targetObject = targetObject; 
    
            Enhancer enhancer = new Enhancer(); // 该类用于生成代理对象
            enhancer.setSuperclass(this.targetObject.getClass()); // 设置目标类为代理对象的父类
            enhancer.setCallback(this); // 设置回调用对象为本身
    
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            PersonServiceBean bean = (PersonServiceBean)this.targetObject;
            Object result = null; 
            if (bean.getUser() != null) { // 有权限
                result = methodProxy.invoke(targetObject, args); // 把方法调用委派给目标对象
            }
            return result;
        }
    }
    • 1

    结论:CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。 
    接着就要修改AOPTest类的代码了,我们先将AOPTest类的代码改为:

    public class AOPTest {
    
        @Test
        public void proxyTest() {
            JDKProxyFactory factory = new JDKProxyFactory();
            PersonService service = (PersonService) factory.createProxyInstance(new PersonServiceBean());
            service.save("888");
        }
    
        @Test
        public void proxyTest2() {
            CGlibProxyFactory factory = new CGlibProxyFactory();
            PersonServiceBean service = (PersonServiceBean) factory.createProxyInstance(new PersonServiceBean("xxx"));
            service.save("999");
        }
    
    }
    • 1
    • 2

    测试proxyTest2()方法,Eclipse控制台会打印: 
    这里写图片描述 
    若是将AOPTest类的代码改为:

    public class AOPTest {
    
        @Test
        public void proxyTest() {
            JDKProxyFactory factory = new JDKProxyFactory();
            PersonService service = (PersonService) factory.createProxyInstance(new PersonServiceBean());
            service.save("888");
        }
    
        @Test
        public void proxyTest2() {
            CGlibProxyFactory factory = new CGlibProxyFactory();
            PersonServiceBean service = (PersonServiceBean) factory.createProxyInstance(new PersonServiceBean());
            service.save("999");
        }
    
    }
    • 1

    再次测试proxyTest2()方法,Eclipse控制台什么都不会打印。 
    如要查看源码,可点击使用JDK中的Proxy技术实现AOP功能与使用CGLIB实现AOP功能进行下载。

    AOP概念解释

    AOP用在哪些方面:AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制,异常处理等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

    AOP中的概念

    Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。 
    joinpoint(连接点):所谓连接点是指那些被拦截到的点(可以是方法、属性、或者类的初始化时机(可以是Action层、Service层、dao层))。在Spring中,这些点指的是方法,因为Spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器。 
    Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义,也即joinpoint的集合。 
    Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知。我们就以CGlibProxyFactory类的代码为例进行说明:

    public class CGlibProxyFactory implements MethodInterceptor {
        private Object targetObject; // 代理的目标对象
    
        public Object createProxyInstance(Object targetObject) {
            this.targetObject = targetObject; 
    
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(this.targetObject.getClass()); // 设置目标类为代理对象的父类
            enhancer.setCallback(this);
    
            return enhancer.create();
        }
    
        // 从另一种角度看: 整个方法可看作环绕通知
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            PersonServiceBean bean = (PersonServiceBean)this.targetObject;
            Object result = null; 
            if (bean.getUser() != null) { // 有权限
                // ...... advice() ----> 前置通知(所谓通知,就是我们拦截到业务方法之后所要干的事情)
                try {
                    result = methodProxy.invoke(targetObject, args); // 把方法调用委派给目标对象
                    // ...... afteradvice() ----> 后置通知
                } catch (RuntimeException e) {
                    // ...... exceptionadvice() ----> 异常通知
                } finally {
                    // ...... finallyadvice() ----> 最终通知
                }
            }
            return result;
        }
    }

    Target(目标对象):代理的目标对象。 
    Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入。 
    Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类(代理类)动态地添加一些方法或Field。 
    AOP带来的好处:降低模块的耦合度;使系统容易扩展;更好的代码复用性

  • 相关阅读:
    java学习:字符串比较“==”与“equals”的差异及与c#的区别
    航空8联货运单的作用详解
    flash:二次贝塞尔曲线应用生成飞机路径示意图
    javascript:双链表插入排序
    javascript:算法笔记
    玩聚RT 加入对饭否的统计
    随手小记:创业瞎聊十点
    Python的win32serviceutil之疑似BUG
    撕书记忆法
    中文锐推榜优化·二
  • 原文地址:https://www.cnblogs.com/telwanggs/p/6913335.html
Copyright © 2020-2023  润新知