本篇换成使用 CGLibCode Generation Library 这个库的方式来进行类方法 (AOP) 拦截
1. CGLib 作用:
CGLIB(Code Generation Library)是一个开源项目, 是一个强大的, 高性能, 高质量的 Code 生成类库, 它可以在运行期扩展 Java 类与实现 Java 接口, 通俗说 cglib 可以在运行时动态生成字节码
2. CGLib 的 maven 地址:
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>3.2.5</version>
- <scope>compile</scope>
- </dependency>
3. 声明一个演示用的类(不是接口), 该类有两个构造函数(无参及带参):
- public class CGLibBean {
- private String name;
- private String age;
- //1. 无参构造函数
- public CGLibBean(){
- this.name = "jacky";
- this.age = "18";
- }
- //2. 带参构造函数
- public CGLibBean(String name,String age) {
- this.name = name;
- this.age = age;
- }
- //3. get/set 函数
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- }
4. 使用 CGLib 进行类的成员方法拦截:
要用到的包及类
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
声明一个类, 实现 net.sf.cglib.proxy.MethodInterceptor 接口, 该接口继承自 Callback 标记接口
- public class CGLibProxy implements MethodInterceptor
- // 空接口
- public interface Callback
- {
- }
- public interface MethodInterceptor extends Callback
- {
- /**
- * All generated proxied methods call this method instead of the original method.
- * The original method may either be invoked by normal reflection using the Method object,
- * or by using the MethodProxy (faster).
- * @param obj "this", the enhanced object
- * @param method intercepted Method
- * @param args argument array; primitive types are wrapped
- * @param proxy used to invoke super (non-intercepted method); may be called
- * as many times as needed
- * @throws Throwable any exception may be thrown; if so, super method will not be invoked
- * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
- * @see MethodProxy
- */
- public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
- MethodProxy proxy) throws Throwable;
- }
实现两个方法, 用于代理生成无参和带参的代理对象
- public Object createProxy(Class<?> target){
- Enhancer enhancer = new Enhancer();
- // 设置要代理的目标类对象
- enhancer.setSuperclass(target);
- // 设置 callback
- enhancer.setCallback(this);
- // 如果你希望 CGLIB 创建一个有参数的实例, 你应该使用 net.sf.cglib.proxy.Enhancer.create(Class[], Object[])
- // 该方法的第一个参数指明参数类型, 第二个参数指明参数值参数中的原子类型需要使用包装类
- return enhancer.create();
- }
- public Object createProxyWithStringParams(Class<?> target){
- Enhancer enhancer = new Enhancer();
- // 设置要代理的目标类对象
- enhancer.setSuperclass(target);
- // 设置 callback
- enhancer.setCallback(this);
- // 如果你希望 CGLIB 创建一个有参数的实例, 你应该使用 net.sf.cglib.proxy.Enhancer.create(Class[], Object[])
- // 该方法的第一个参数指明参数类型, 第二个参数指明参数值参数中的原子类型需要使用包装类
- @SuppressWarnings("rawtypes")
- Class[] types = new Class[2];
- types[0] = String.class;
- types[1] = String.class;
- Object[] objs = new String[2];
- objs[0] = "tom";
- objs[1] = "16";
- // 生成一个名为 tom, 年龄 16 岁的对象
- return enhancer.create(types,objs);
- }
实现 MethodInterceptor 接口中的 intercept 方法
- public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- System.out.println("before from"+method.getName());
- // 比较重要的一个方法, invokeSuper, 实际调用的是 CGLibBean 中的方法
- Object ret = proxy.invokeSuper(obj, args);
- System.out.println("after from"+method.getName());
- return ret;
- }
5. 测试代码:
使用无参函数
- public static void testCGLib(){
- CGLibProxy proxy = new CGLibProxy();
- CGLibBean obj = (CGLibBean)proxy.createProxy(CGLibBean.class);
- obj.getName();
- obj.getAge();
- }
使用有参函数
- public static void testCGLibWithParams() {
- CGLibProxy proxy = new CGLibProxy();
- CGLibBean obj = (CGLibBean) proxy.createProxyWithStringParams(CGLibBean.class);
- obj.getName();
- obj.getAge();
- }
main 函数:
- public static void main(String[] args) {
- System.out.println("blf test demo");
- testCGLib();
- System.out.println("---------------------------");
- testCGLibWithParams();
- }
显示效果如下:
- blf test demo
- before from getName
- after from getName
- before from getAge
- after from getAge
- ---------------------------
- before from getName
- after from getName
- before from getAge
- after from getAge
CGLib 的缺陷:
不能对 final 类型进行 aop 拦截
到目前为止, 我们已经了解了三种 AOP 的实现方式, 各有优缺点
之所以讲这么多, 是为了更好的理解 Spring 中的 AOP
实际 Spring 中的 AOP 就是使用了上面提到的那些技术, 进行了强大的二次封装
来源: http://www.jianshu.com/p/78799a55cbc2