Spring AOP(面向切面编程)使用了两种技术实现,一种是JDK自带的动态代理,另外一种是使用cglib字节码技术动态生成代理类。Spring是如何选择的了:
- 如果目标对象实现了接口,默认情况先回选择使用JDK代理技术实现AOP,但是也可以强制使用cglib实现动态代理
- 如果目标对象没有实现接口,则会采用cglib技术实现AOP
cglib创建某个动态代理类的模式是:
- 查找目标类上所有非 final 的public类型的方法,将这些方法的定义转换成字节码
- 将组成的字节码转换成相应的代理的class对象
- 代理类实现MethodInterceptor接口,用来处理代理类上所有方法的请求(中介)
下面是代码:
定义一个通用接口,里面定义一些要拦截的方法
package com.minglangx.cglib;
/**
*
* @ClassName: UserService
* @Description: 通用接口类
* @author minglangx
* @date 2017年8月19日 下午12:02:34
*
*/
public interface UserService {
String getName(String name);
Integer getAge(int age);
}
定义一个目标对象,实现这个通用接口
package com.minglangx.cglib;
/**
*
* @ClassName: UserServiceImpl
* @Description: 目标对象
* @author minglangx
* @date 2017年8月19日 下午12:02:52
*
*/
public class UserServiceImpl implements UserService {
@Override
public String getName(String name) {
System.out.println("===getName===");
return name;
}
@Override
public Integer getAge(int age) {
System.out.println("====getAge=====");
return age;
}
}
核心代理类,实现MethodInterceptor接口
package com.minglangx.cglib;
import java.lang.reflect.Method;
import java.util.Arrays;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
*
* @ClassName: CglibDemo
*
* @Description: 代理类使用 Cglib实现动态代理
*
* @author minglangx
*
* @date 2017年8月18日 下午12:33:51
*
*
*
*
*
*/
class CglibDemo implements MethodInterceptor {
/**
* Object obj 被代理的对象
* Method method 被拦截的方法
* Object[] objs 方法的参数
* MethodProxy methodProxy cglib中的代理对象
*
*
*/
@Override
public Object intercept(Object obj, Method method, Object[] objs, MethodProxy methodProxy) throws Throwable {
System.out.println("======before " + methodProxy.getSuperName() + "======");
System.out.println("被拦截的方法名称-----" + method.getName());
System.out.println("被拦截的方法参数-----" + Arrays.asList(objs));
//invokeSuper(obj,objs) 第一个参数是被代理对象,第二个参数是参数集合
Object objNew = methodProxy.invokeSuper(obj, objs);
System.out.println("+++++before " + methodProxy.getSuperName() + "=====");
return objNew;
}
}
测试类
- 使用 Enhancer().setSuperclass(目标对象); 设置要代理的对象
- 使用 Enchancer.setCallback(目标对象); 将要代理对象的所有方法都转发到intercept()方法上进行拦截
- 使用Enchancer.create();获取被代理的对象
package com.minglangx.cglib;
import net.sf.cglib.proxy.Enhancer;
import com.minglangx.cglib.UserService;
import com.minglangx.cglib.UserServiceImpl;
public class MainDemo {
public static void main(String[] args) {
CglibDemo cglibDemo = new CglibDemo();
//cglib中的加强器,用来创建动态代理
Enhancer enhancer = new Enhancer();
//设置要动态创建的类
enhancer.setSuperclass(UserServiceImpl.class);
/*
* 设置回调.这里相当于是对于代理类上所有方法的回调,都会调用CallBack,
* 而Callback需要执行intercept()方法进行拦截
*/
enhancer.setCallback(cglibDemo);
//得到实际对象的接口类型,调用其方法
UserService o =(UserService) enhancer.create();
o.getName("zhangs");
o.getAge(25);
}
}
输出结果: 我们看到在被代理对象调用方法之前成功实现了方法的拦截