Spring第九弹—使用CGLIIB实现AOP功能与AOP概念解释
JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理,原理之前我已经讲过。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包。
PS:需要引入com.springsource.net.sf.cglib-2.2.0.jar包。
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如:Spring AOP和dynaop,为他们提供方法的interception(拦截); 它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 (CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。)
使用Cglib包生成代理的模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class CGLIBProxy 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();
}
public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {
return methodProxy.invoke(this.targetObject, args);
}
}
|
第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。通过使用java.lang.reflect.Method对象的一般反射调用或者使用net.sf.cglib.proxy.MethodProxy对象调用都可以完成对原方法的调用,但是通常net.sf.cglib.proxy.MethodProxy对象被首选使用,因为它更快。
PS:net.sf.cglib.proxy.MethodProxy应该是cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升。
示例:
Service类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package net.zmcheng.service;
public class PersonService {
private String name;
public PersonService(){
super();
}
public PersonService(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void save(){
System.out.println("我是save方法");
}
}
|
Cglib动态代理工厂:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package net.zmcheng.aop;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.zmcheng.service.PersonService;
public class CglibProxyFactory implements MethodInterceptor{
public Object targetObject;
public Object createProxyIntance(Object targetObject){
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();//该类用于生成代理对象
enhancer.setSuperclass(this.targetObject.getClass());//设置父类
enhancer.setCallback(this);//设置回调用对象为本身
return enhancer.create();//创建代理对象
}
//MethodInterceptor接口类似于jdk中的java.lang.reflect.InvocationHandler接口
// MethodInterceptor中的intercept方法同java.lang.reflect.InvocationHandler接口中的 invoke方法类似
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){//环绕通知
PersonService bean = (PersonService)this.targetObject;
Object result = null;
if(bean.getName()!=null){
//....advice()--->前置通知
try {
result = method.invoke(targetObject, args);
//..afteradvice()--->后置通知
} catch (Exception e) {
//....exceptionadvice()--->例外通知
e.printStackTrace();
}finally{
//finallyadvice();----->最终通知
}
}
return result;
}
}
|
测试类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.zmcheng.test;
import org.junit.BeforeClass;
import org.junit.Test;
import net.zmcheng.aop.CglibProxyFactory;
import net.zmcheng.service.PersonService;
public class aopTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void test() {
CglibProxyFactory factory = new CglibProxyFactory ();
PersonService service = (PersonService)factory.createProxyIntance(new PersonService("zmc"));
service.save();
}
}
|
输出结果:我是save方法
AOP中的概念:
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象.
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.