一、CGlib 动态代理
JDK 实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要 CGLib 了。CGLib 采用了非常底层的 1:字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用 2:方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK 动态代理与 CGLib 动态代理均是实现 Spring AOP 的基础。
CGLib 创建的动态代理对象性能比 JDK 创建的动态代理对象的性能高不少,但是 CGLib 在创建代理对象时所花费的时间却比 JDK 多得多,所以对于单例的对象,因为无需频繁创建对象,用 CGLib 合适,反之,使用 JDK 方式要更为合适一些。同时,由于 CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理。
简单的实现举例:
这是一个需要被代理的类,也就是父类,通过字节码技术创建这个类的子类,实现动态代理。
[java] view plaincopy
1. publicclass SayHello {
2. publicvoid say(){
3. System.out.println("hello everyone");
4. }
5. }
该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class) 方法通过入参即父类的字节码,通过扩展父类的 class 来创建代理对象。intercept() 方法拦截所有目标类方法的调用,obj 表示目标类的实例,method 为目标类方法的反射对象,args 为方法的动态入参,proxy 为代理类实例。proxy.invokeSuper(obj, args) 通过代理类调用父类中的方法。
[java] view plaincopy
1. publicclass CglibProxy implements MethodInterceptor{
2. private Enhancer enhancer = new Enhancer();
3. public Object getProxy(Class clazz){
4. // 设置需要创建子类的类
5. enhancer.setSuperclass(clazz);
6. enhancer.setCallback(this);
7. // 通过字节码技术动态创建子类实例
8. return enhancer.create();
9. }
10.// 实现 MethodInterceptor 接口方法
11.public Object intercept(Object obj, Method method, Object[] args,
12. MethodProxy proxy) throws Throwable {
13. System.out.println("前置代理");
14. // 通过代理类调用父类中的方法
15. Object result = proxy.invokeSuper(obj, args);
16. System.out.println("后置代理");
17. return result;
18. }
19.}
具体实现类:
[java] view plaincopy
1. publicclass DoCGLib {
2. publicstaticvoid main(String[] args) {
3. CglibProxy proxy = new CglibProxy();
4. // 通过生成子类的方式创建代理类
5. SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
6. proxyImp.say();
7. }
8. }
输出结果:
[plain] view plaincopy
1. 前置代理
2. hello everyone
3. 后置代理
二、JDK 动态代理
使用动态代理的五大步骤
1. 通过实现 InvocationHandler 接口来自定义自己的 InvocationHandler;
2. 通过 Proxy.getProxyClass 获得动态代理类
3. 通过反射机制获得代理类的构造方法,方法签名为 getConstructor(InvocationHandler.class)
4. 通过构造函数,获得代理对象,并将自定义的 InvocationHandler 实例对象传为参数传入
5. 通过代理对象调用目标方法
public class ObjectProxy implements InvocationHandler {
Object target = null;
List<BeforeAdvice> beforeList = new ArrayList<BeforeAdvice>();
List<AfterAdvice> afterList = new ArrayList<AfterAdvice>();
public ObjectProxy() {
super();
// TODO Auto-generated constructor stub
}
public ObjectProxy(Object target) {
super();
this.target = target;
try{
// 解析 advice.xml 中所有的前置通知 -- 得到 class 的值 ---> 通过反射得到类的对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("src//advice.xml");
// 遍历前置通知
NodeList beforeNodeList = doc.getElementsByTagName("beforeAdvice");
for(int i=0;i<beforeNodeList.getLength();i++){
Element beforeElement =(Element) beforeNodeList.item(i);
String classValue = beforeElement.getAttribute("class"); // 类的完整路径
Class clz = Class.forName(classValue);
BeforeAdvice obj = (BeforeAdvice)clz.newInstance();
beforeList.add(obj);
}
// 遍历后置通知
NodeList afterNodeList = doc.getElementsByTagName("afterAdvice");
for(int i=0;i<afterNodeList.getLength();i++){
Element afterElement =(Element) afterNodeList.item(i);
String classValue = afterElement.getAttribute("class"); // 类的完整路径
Class clz = Class.forName(classValue);
AfterAdvice obj = (AfterAdvice)clz.newInstance();
afterList.add(obj);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 伪装成目标类之后,要执行的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 短信验证
for(BeforeAdvice bf:beforeList){
// 对 method 目标方法进行判断,执行响应的前置切面业务
bf.Before();
}
// 目标方法
Object result = method.invoke(target, args);
// 日志记录
for(AfterAdvice af:afterList){
// 对 method 目标方法进行判断,执行响应的后置切面业务
af.After();
}
return result;
}
/**
* 获得代理类的对象
* @param obj
* @return
*/
public static Object getProxyBean(Object obj){
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),new ObjectProxy(obj));
}
}
public static void main(String[] args) {
Idog dog = (Idog)ObjectProxy.getProxyBean(new Dog());
dog.say();
}
来源: http://www.bubuko.com/infodetail-2432730.html