最近一直在加班,迟迟没有更博,今天就来和大家一起继续聊一聊AOP的实现原理,记得在上一篇博客中和大家聊了一下使用动态代理的方式实现AOP,通过上一篇博客给大家应该能够感觉得到,JDK 的动态代理使用起来非常的简单和方便。那么是不是所有的情况都适合使用动态代理的方式去实现AOP呢?
这里先来给大家介绍几个和AOP相关的名词,
Joinpoint(切入点):是指的被拦截到的点,在spring中可以被目标代理拦截的目标类的方法,根据上一篇博客中的案例来讲的话的就是指的UserDaoImpl类中的方法。
Advice(通知):指的就是对目标对象中的方法进行增强的内容
Target(目标):指的目标对象,也就是UserdaoImpl的对象.
Weaving(织入):通俗的来讲就是指的生成目标对象的过程,也叫织入的过程
Proxy(代理):指的生成的代理对象
Aspect(切面):这个概念有点抽象这里给出《spring实战第四版》中的解释:
很抽象把,大家可以粗糙的理解成通知和切点在一起的时候他们就成了切面,就像你和你女朋友在一起的时候组和成了情侣,这个时候别人就可以说你们是一对情侣。同样的,当通知和切入点在一起的时候,他们就叫做切面。所谓的面向切面编程,我的理解就是面向通知和切点编程。
好了,给大家解释了一下AOP中的几个术语。下面我们在文章中可能会涉及到上述的术语,相信大家都记得,上一篇博客中的目标类是实现了一个UserDao接口,那么问题来了,假设通知类没有实现接口呢?那么我们应该如何去使用动态代理去实现AOp呢?
这里给大家解释一下,如果要实现动态代理就必须要有接口,没有接口就不能使用动态代理,关于这原因将会在后面的博客中给大家专门的介绍,如果大家确实想知道的话可以反编译一下被代理的类,或许就会发现原因了。
好了,回到今天的主题上,假如Target类没有实现接口我们怎么去实现动态代理呢?前面提到过,Spring中提供了两种实现AOP的方式,那么上一篇博客中我们手动的使用JDK动态代理来实现了AOP,好了今天我们就用另外的一种方式来手动实现一下AOP。这种方式就是CGLIB代理。
在Spring中的核心包下已经帮我们集成了Cglib所依赖的jar包,因此,我们在使用Cglib来手动实现AOP的时候需要引入Cglib所依赖的jar包。也可以直接使用spring中的core(核心包),在该包下有一个很轻便的字节码处理框架,ASM(Java字节码操控框架)来转换字节码,为一个类来创建子类,通过子类来增强目标类的方法,解决了无接口代理的问题。
好了,打开eclipse,新建一个工程,将spring-core包,并添加到path,打开core包,发现该包的结构如下图所示:
其中asm就是我们需要的字节码操控框架,cglib包下封装了用于实现AOP的一些类库。好了,在工程下来创建一个包,包结构如下图所示:
先来在dao包下创建一个类UserDao,同样的在该类中定四个增删改查的方法,具体代码如下图所示:
public class UserDao {
public void save() {
// TODO Auto-generated method stub
System.out.println("添加用户执行了");
}
public void update() {
// TODO Auto-generated method stub
System.out.println("更新用户执行了");
}
public void delete() {
// TODO Auto-generated method stub
System.out.println("删除用户执行了");
}
public void find() {
// TODO Auto-generated method stub
System.out.println("查询用户执行了");
}
}
接着和上次一样,来定义一个对目标进行增强的类,代码如下:
//对方法增强的类
public class Aspect {
public void before() {
System.out.println("【**********开启事务**********");
}
public void after() {
System.out.println("**********提交事务**********】");
}
}
接着就来编写代理类了,具体代码如下所示:
public class MyBeanFactory {
public static UserDao getBean() {
final UserDao dao = new UserDao();
// 创建 切面类 实例
final Aspect aspect = new Aspect();
// 生成代理类,cglib在运行时,生成指定对象的子类,增强
Enhancer enhancer = new Enhancer();
// 确定需要增强的类
enhancer.setSuperclass(dao.getClass());
// 添加回调函数
enhancer.setCallback(new MethodInterceptor() {
// intercept相当于 jdk invoke , 前三个参数与jdk invoke一致
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
//1 、之前
aspect.before();
//2 、目标方法执行
Object obj = method.invoke(dao, args);
//3、 之后
aspect.after();
return obj;
}
});
// 创建代理类
UserDao daoProxy = (UserDao) enhancer.create();
return daoProxy;
}
}
解释一下这段代码, 上述代码中Enhancer类便是cglib的核心类,通过该类的setSuperclass方法来确定目标对象,接着调用setCallback()方法添加回调函数,接下的就传入一个MethodInterceptor对象,重写intercept方法,该方法和JDK的动态代理中的invoke方法类似,功能就是在目标方法执行的前后调用切面类中的方法对目标方法进行增强。最后通过enhancer的create方法创建目标类的代理对象,并将该代理对象返回。
好了,通过cglib创建代理对象的实现AOP的方式的整个过程就是这样了,接下来就来测试一下这种方式吧,创建测试类,代码如下:
public class CglibTest {
@Test
public void cglibTest() {
UserDao dao = MyBeanFactory.getBean();
dao.delete();
dao.find();
dao.save();
dao.update();
}
}
调用UserDao对象的中的基本的方法,运行结果 如下图所示:
看,UserDao中的基本方法都被增强了,这就是使用Cglib实现代理的方式,实现AOP的代理模式的基本原理就是这样的,好了,希望大家都有自己的收获,到这里就已经给大家详细的介绍了Spring中的IOC和AOP两个基本的核心模块了,大家现在应该都能知道了Spring框架中的实现原理了吧。在后续的博客中将会带着大家继续学习Spring框架。如果大家想要学好Spring框架以及基于spring技术栈相关的技术的话前提就是要学好这两个基础概念。好了今天就到这里吧。
下一篇博客继续给大家介绍Spring中的bean。