19.动态代理-cglib

 

动态代理-cglib

cglib的实现原理:
在内存里构造一个目标对象的子类对象,
返回一个目标对象的子类对象的代理对象。

向项目中添加jar包:

  • asm-4.2.jar
  • cglib-3.1.jar

UserDaoImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.course.dao.impl;

public class UserDaoImpl {

public void addUser(String userName) {
System.out.println("Save user, userName = " + userName);

}

public void deleteUser(Integer userId) {
System.out.println("delete user, userId = " + userId);

}

public void queryUser(Integer userId) {
System.out.println("query user, user[userId=" + userId + ", userName=Jerry]");

}
}

ProxyFactory

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.course.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class ProxyFactory implements MethodInterceptor {

// 目标对象
private Object targetObject;

public ProxyFactory(Object targetObject) {
this.targetObject = targetObject;
}

/**
* 拦截方法
* 参数说明:
* - Object obj: 目标对象
* - Method method: 目标对象所调用的方法
* - Object[] args: 目标对象所调用的方法的参数
* - MethodProxy proxy: 方法代理
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
openTransaction();
Object invoke = method.invoke(targetObject, args);
commitTransaction();
return invoke;
}

/**
* 得到代理对象
* @return: 代理对象
*/
public Object getProxyInstance() {
// 1.创建一个目标对象的子类对象的构造方法
Enhancer enhancer = new Enhancer();
// 2.设置父类为目标对象
enhancer.setSuperclass(targetObject.getClass());
// 3.设置回调为当前工厂类
/*
* setCallback(Callback callback)
* ProxyFactory implements MethodInterceptor
* MethodInterceptor extends Callback
*/
enhancer.setCallback(this);
// 4.在内存中生成代理对象
Object proxy = enhancer.create();
return proxy;
/*
* 1-3相当于定义了一个目标类的子类: public class SubTargetObject extends targetObject
* 4相当于创建了一个目标类的子类对象: SubTargetObject subTargetObject = new SubTargetObject();
*/

}

public void openTransaction() {
System.out.println("open transaction");
}

public void commitTransaction() {
System.out.println("commit transaction");
}
}

测试类

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
package com.course.test;

import com.course.dao.impl.UserDaoImpl;
import com.course.proxy.ProxyFactory;

public class Test {

public static void main(String[] args) {
// 创建一个目标对象
UserDaoImpl userDaoImpl = new UserDaoImpl();
// 创建代理工厂对象
ProxyFactory userDaoImplProxyFactory = new ProxyFactory(userDaoImpl);
// 得到代理对象
UserDaoImpl UserDaoImplProxy = (UserDaoImpl) userDaoImplProxyFactory.getProxyInstance();
// 执行目标方法
String userName = "Tom";
UserDaoImplProxy.addUser(userName);
/*
* open transaction
* Save user, userName = Tom
* commit transaction
*/
Integer userId = 1;
UserDaoImplProxy.deleteUser(userId);
/*
* open transaction
* delete user, userId = 1
* commit transaction
*/
userId = 2;
UserDaoImplProxy.queryUser(userId);
/*
* open transaction
* query user, user[userId=2, userName=Jerry]
* commit transaction
*/

}
}

总结

在Spring的AOP编程中,

如果加入容器的目标对象实现了接口,使用JDK动态代理

如果加入容器的目标对象没有实现接口,使用cglib动态代理

内部类

$是内部类的标志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.course.test;

import com.course.dao.impl.UserDaoImpl;
import com.course.proxy.ProxyFactory;

public class Test {

public static void main(String[] args) {
// 创建一个目标对象
UserDaoImpl userDaoImpl = new UserDaoImpl();
// 创建代理工厂对象
ProxyFactory userDaoImplProxyFactory = new ProxyFactory(userDaoImpl);
// 得到代理对象
UserDaoImpl UserDaoImplProxy = (UserDaoImpl) userDaoImplProxyFactory.getProxyInstance();
System.out.println(UserDaoImplProxy.getClass().getSimpleName());
// UserDaoImpl$$EnhancerByCGLIB$$e098f0e3
}
}

一个.java文件可以编译生成多个.class文件,数量取决于.java文件中定义的class类的数量

一个.java文件只能有一个public class

如果不是内部类,编译生成类名.class,如果是内部类,生成外部类$内部类.class