使用CGLIB实现AOP功能与AOP概念解释

使用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带来的好处:降低模块的耦合度;使系统容易扩展;更好的代码复用性

时间: 2024-10-12 21:49:55

使用CGLIB实现AOP功能与AOP概念解释的相关文章

Spring第九弹—使用CGLIIB实现AOP功能与AOP概念解释

JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理,原理之前我已经讲过.JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口.如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包. PS:需要引入com.springsource.net.sf.cglib-2.2.0.jar包. CGLIB是一个强大的高性能的代码生成包.它广泛的被许多AOP的框架使用,例如:Spring AOP和dynaop,为他们提供方法的int

SpringBoot中使用LoadTimeWeaving技术实现AOP功能

目录 1. 关于LoadTimeWeaving 1.1 LTW与不同的切面织入时机 1.2 JDK实现LTW的原理 1.3 如何在Spring中实现LTW 2. Springboot中使用LTW实现AOP的例子 3. 参考资料 1. 关于LoadTimeWeaving 1.1 LTW与不同的切面织入时机 AOP--面向切面编程,通过为目标类织入切面的方式,实现对目标类功能的增强.按切面被织如到目标类中的时间划分,主要有以下几种: 1.运行期织入 这是最常见的,比如在运行期通过为目标类生成动态代理

Spring AOP学习笔记(1)-概念

1.Aspect 横切在多个类的一个关注点,在Spring AOP中,aspect实现是一个规则的类或@Aspect标注的规则类.例如:事务管理 2.Join point 程序执行过程中的一个点,例如:执行一个方法或处理一个异常,在Spring AOP中,一个连接点表示一个方法执行执行 3.Advice 在一个特定的连接点上所采取的动作,类型包括around,before,after等,Spring中 advice就是一个interceptor模式,包括around连接点的interceptor

java Instrument修改字节码实现aop功能

Agent工程2个类: public class MyAgent { /** * 该方法在main方法之前运行,与main方法运行在同一个JVM中 * 并被同一个System ClassLoader装载 * 被统一的安全策略(security policy)和上下文(context)管理 */ public static void premain(String agentOps, Instrumentation inst) { System.out.println("=========prema

你相信么,只需一个函数5行JS代码即可在Javascript中实现完整的AOP功能

你相信么,只需一个函数5行JS代码即可在Javascript中实现完整的AOP功能, 你相信么,在JavaScript只需一个函数5行代码即可实现完整的面向方面AOP编程功能.这5行代码的功能包括: 无限层次的函数无害拦截 函数执行前拦截 检查函数的参数值 重新设定函数的参数值 函数执行后拦截 检查函数执行后的返回结果 重新设定函数的返回结果 虽然动态函数式语言的效率是一个存在的问题,但是对于它的高度灵活性,简直让人令人惊叹不已,剧赞. 这个小小的函数源自于和爱明兄的一次讨论:在javascri

实现AOP功能的封装与配置的小框架

内容 java基础巩固笔记 - 实现AOP功能的封装与配置的小框架 设计(目录): XXX = java.util.ArrayList中 代码 Advice接口 MyAdvice类 BeanFactory类 ProxyFactoryBean类 AopFrameWorkTest类 输出 本文通过是动态代理实现的AOP功能的封装与配置的小框架.加深对动态代理和AOP编程的理解 获取源码,学习交流,那就加入小编的学习交流群吧!616 959 444 设计 根据配置文件的键xxx对应的值(类全名)创建相

C# Unity依赖注入利用Attribute实现AOP功能

使用场景? 很多时候, 我们定义一个功能, 当我们要对这个功能进行扩展的时候, 按照常规的思路, 我们一般都是利用OOP的思想, 在原有的功能上进行扩展. 那么有没有一种东西, 可以实现当我们需要扩展这个功能的时候, 在不修改原来的功能代码的情况下实现, 这就是下面要说的到Unity. 1.准备工作 为项目添加NuGet包, 搜索Unity并且安装. 在使用的项目中添加Unity的相关引用 using Microsoft.Practices.Unity.InterceptionExtension

FreeSql aop功能介绍

前言 FreeSql 是一个功能强大的 .NETStandard 库,用于对象关系映射程序(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.6.1+(QQ群:4336577). 据了解,用户使用很少问问题,编码过程中,因业务阻塞,情有可原:因框架使用问题阻塞,得不偿失.我们的口号:做 .net 最方便的 ORM!愿每一位开发者嘴角上扬??! 整体功能 IFreeSql 是核心,提供原始用法: FreeSql.DbContext 是扩展包,提供面向对象的用法(像E

[开源] FreeSql AOP 功能模块

前言 FreeSql 是一个功能强大的 .NETStandard 库,用于对象关系映射程序(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.6.1+(QQ群:4336577). 据了解,用户使用很少问问题,编码过程中,因业务阻塞,情有可原:因框架使用问题阻塞,得不偿失.我们的口号:做 .net 最方便的 ORM!愿每一位开发者嘴角上扬??! 整体功能 IFreeSql 是核心,提供原始用法: FreeSql.DbContext 是扩展包,提供面向对象的用法(像E